home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr47 / modex100.zip / MODEX.ASM < prev    next >
Assembly Source File  |  1993-05-07  |  93KB  |  3,157 lines

  1. ;========================================================
  2. ; MODEX.ASM - A Complete Mode X Library
  3. ;
  4. ; Version 0.99 Beta, 29 March 1993, By Matt Pritchard
  5. ; With considerable input from Michael Abrash
  6. ;
  7. ; The following information is donated to the public domain in
  8. ; the hopes that save other programmers much frustration.
  9. ;
  10. ; If you do use this code in a product, it would be nice if
  11. ; you include a line like "Mode X routines by Matt Pritchard"
  12. ; in the credits.
  13. ;
  14. ; =========================================================
  15. ;
  16. ; All of this code is designed to be assembled with MASM 5.10a
  17. ; but TASM 3.0 could be used as well.  
  18. ;
  19. ; The routines contained are designed for use in a MEDIUM model
  20. ; program.  All Routines are FAR, and is assumed that a DGROUP
  21. ; data segment exists and that DS will point to it on entry.
  22. ;
  23. ; For all routines, the AX, BX, CX, DX, ES and FLAGS registers 
  24. ; will not be preserved, while the DS, BP, SI and DI registers
  25. ; will be preserved.
  26. ;
  27. ; Unless specifically noted, All Parameters are assumed to be 
  28. ; "PASSED BY VALUE".  That is, the actual value is placed on
  29. ; the stack.  When a reference is passed it is assumed to be
  30. ; a near pointer to a variable in the DGROUP segment.
  31. ;
  32. ; Routines that return a single 16-Bit integer value will 
  33. ; return that value in the AX register.
  34. ;
  35. ; This code will *NOT* run on an 8086/8088 because 80286+ 
  36. ; specific instructions are used.   If you have an 8088/86
  37. ; and VGA, you can buy an 80386-40 motherboard for about
  38. ; $160 and move into the 90's.
  39. ;
  40. ; This code is reasonably optimized: Most drawing loops have
  41. ; been unrolled once and memory references are minimized by
  42. ; keeping stuff in registers when possible.
  43. ;
  44. ; Error Trapping varies by Routine.  No Clipping is performed
  45. ; so the caller should verify that all coordinates are valid.
  46. ;
  47. ; Several Macros are used to simplify common 2 or 3 instruction 
  48. ; sequences.  Several Single letter Text Constants also 
  49. ; simplify common assembler expressions like "WORD PTR".
  50. ;
  51. ; ------------------ Mode X Variations ------------------
  52. ;  Mode #  Screen Size    Max Pages   Aspect Ratio (X:Y)
  53. ;
  54. ;    0      320 x 200      4 Pages         1.2:1
  55. ;    1      320 x 400      2 Pages         2.4:1
  56. ;    2      360 x 200      3 Pages        1.35:1
  57. ;    3      360 x 400      1 Page          2.7:1
  58. ;    4      320 x 240      3 Pages           1:1
  59. ;    5      320 x 480      1 Page            2:1
  60. ;    6      360 x 240      3 Pages       1.125:1
  61. ;    7      360 x 480      1 Page         2.25:1
  62. ;
  63. ; -------------------- The Legal Stuff ------------------
  64. ;
  65. ; No warranty, either written or implied, is made as to 
  66. ; the accuracy and usability of this code product.  Use 
  67. ; at your own risk.  Batteries not included.  Pepperoni 
  68. ; and extra cheese available for an additional charge.
  69. ; ----------------------- The Author --------------------
  70. ;
  71. ; Matt Pritchard is a paid programmer who'd rather be
  72. ; writing games.  He can be reached at: P.O. Box 140264,
  73. ; Irving, TX  75014  USA.  Michael Abrash is a living 
  74. ; god, who now works for Bill Gates (Microsoft). 
  75. ;
  76.  
  77.     PAGE    255, 132
  78.  
  79.     .MODEL Medium
  80.     .286
  81.  
  82.     ; ===== MACROS =====
  83.  
  84.     ; Macro to OUT a 16 bit value to an I/O port
  85.  
  86. OUT_16 MACRO Register, Value
  87.     IFDIFI <Register>, <DX>            ; If DX not setup
  88.         MOV        DX, Register        ; then Select Register
  89.     ENDIF
  90.     IFDIFI <Value>, <AX>            ; If AX not setup 
  91.         MOV        AX, Value            ; then Get Data Value
  92.     ENDIF
  93.         OUT        DX, AX                ; Set I/O Register(s)
  94. ENDM
  95.  
  96.     ; Macro to OUT a 8 bit value to an I/O Port
  97.  
  98. OUT_8 MACRO Register, Value
  99.     IFDIFI <Register>, <DX>            ; If DX not setup
  100.         MOV        DX, Register        ; then Select Register
  101.     ENDIF
  102.     IFDIFI <Value>, <AL>            ; If AL not Setup
  103.         MOV        AL, Value            ; then Get Data Value
  104.     ENDIF
  105.         OUT        DX, AL                ; Set I/O Register
  106. ENDM
  107.  
  108.     ; macros to PUSH and POP multiple registers
  109.  
  110. PUSHx MACRO R1, R2, R3, R4, R5, R6, R7, R8
  111.     IFNB <R1>
  112.         PUSH    R1                ; Save R1
  113.         PUSHx    R2, R3, R4, R5, R6, R7, R8
  114.     ENDIF
  115. ENDM
  116.  
  117. POPx MACRO R1, R2, R3, R4, R5, R6, R7, R8
  118.     IFNB <R1>
  119.         POP        R1                ; Restore R1
  120.         POPx    R2, R3, R4, R5, R6, R7, R8
  121.     ENDIF
  122. ENDM
  123.  
  124.     ; Macro to Clear a Register to 0
  125.  
  126. CLR MACRO Register
  127.     XOR        Register, Register        ; Set Register = 0
  128. ENDM
  129.  
  130.     ; Macros to Decrement Counter & Jump on Condition
  131.  
  132. LOOPx MACRO Register, Destination
  133.     DEC        Register                ; Counter--
  134.     JNZ        Destination                ; Jump if not 0
  135. ENDM
  136.  
  137. LOOPjz MACRO Register, Destination
  138.     DEC        Register                ; Counter--
  139.     JZ        Destination                ; Jump if 0
  140. ENDM
  141.  
  142.  
  143.     ; ===== General Constants =====
  144.  
  145.     False    EQU    0
  146.     True    EQU    -1
  147.     nil        EQU 0
  148.  
  149.     b        EQU    BYTE PTR
  150.     w        EQU    WORD PTR
  151.     d        EQU    DWORD PTR
  152.     o        EQU    OFFSET
  153.     f        EQU FAR PTR
  154.     s        EQU    SHORT
  155.     ?x4        EQU <?,?,?,?>
  156.     ?x3        EQU <?,?,?>
  157.  
  158.     ; ===== VGA Register Values =====
  159.  
  160.     VGA_Segment        EQU    0A000h    ; Vga Memory Segment
  161.  
  162.     ATTRIB_Ctrl        EQU    03C0h    ; VGA Attribute Controller
  163.     GC_Index        EQU    03CEh    ; VGA Graphics Controller
  164.     SC_Index        EQU    03C4h    ; VGA Sequencer Controller
  165.     SC_Data            EQU    03C5h    ; VGA Sequencer Data Port
  166.     CRTC_Index        EQU    03D4h    ; VGA CRT Controller 
  167.     CRTC_Data        EQU 03D5h    ; VGA CRT Controller Data
  168.     MISC_OUTPUT        EQU    03C2h    ; VGA Misc Register
  169.     INPUT_1            EQU 03DAh    ; Input Status #1 Register
  170.  
  171.     DAC_WRITE_ADDR    EQU    03C8h    ; VGA DAC Write Addr Register
  172.     DAC_READ_ADDR     EQU    03C7h    ; VGA DAC Read Addr Register
  173.     PEL_DATA_REG    EQU    03C9h    ; VGA DAC/PEL data Register R/W
  174.  
  175.     PIXEL_PAN_REG    EQU    033h    ; Attrib Index: Pixel Pan Reg
  176.     MAP_MASK        EQU    002h    ; Sequ Index: Write Map Mask reg
  177.     READ_MAP        EQU    004h    ; GC Index: Read Map Register 
  178.     START_DISP_HI    EQU 00Ch    ; CRTC Index: Display Start Hi
  179.     START_DISP_LO    EQU 00Dh    ; CRTC Index: Display Start Lo
  180.  
  181.     MAP_MASK_PLANE1 EQU 00102h    ; Map Register + Plane 1
  182.     MAP_MASK_PLANE2 EQU 01102h    ; Map Register + Plane 1
  183.     ALL_PLANES_ON    EQU 00F02h    ; Map Register + All Bit Planes
  184.  
  185.     CHAIN4_OFF        EQU 00604h    ; Chain 4 mode Off
  186.     ASYNC_RESET        EQU 00100h    ; (A)synchronous Reset
  187.     SEQU_RESTART    EQU 00300h    ; Sequencer Restart
  188.  
  189.     LATCHES_ON        EQU 00008h    ; Bit Mask + Data from Latches
  190.     LATCHES_OFF        EQU 0FF08h    ; Bit Mask + Data from CPU 
  191.  
  192.     VERT_RETRACE    EQU    08h        ; INPUT_1: Vertical Retrace Bit
  193.     PLANE_BITS        EQU 03h        ; Bits 0-1 of Xpos = Plane #
  194.     ALL_PLANES        EQU 0Fh        ; All Bit Planes Selected
  195.     CHAR_BITS        EQU 0Fh        ; Bits 0-3 of Character Data
  196.  
  197.     GET_CHAR_PTR    EQU    01130h    ; VGA BIOS Func: Get Char Set 
  198.     ROM_8x8_Lo        EQU 03h        ; ROM 8x8 Char Set Lo Pointer 
  199.     ROM_8x8_Hi        EQU 04h        ; ROM 8x8 Char Set Hi Pointer 
  200.  
  201.     ; Constants Specific for these routines
  202.  
  203.     NUM_MODES        EQU 8        ; # of Mode X Variations
  204.  
  205.     ; Specific Mode Data Table format... 
  206.  
  207. Mode_Data_Table STRUC
  208.     M_MiscR            DB    ?        ; Value of MISC_OUTPUT register
  209.     M_Pages            DB    ?        ; Maximum Possible # of pages
  210.     M_XSize            DW    ?        ; X Size Displayed on screen
  211.     M_YSize            DW    ?        ; Y Size Displayed on screen
  212.     M_XMax            DW    ?        ; Maximum Possible X Size
  213.     M_YMax            DW    ?        ; Maximum Possible Y Size
  214.     M_CRTC            DW    ?        ; Table of CRTC register values
  215. Mode_Data_Table ENDS
  216.  
  217.     ; ===== DGROUP STORAGE NEEDED (42 BYTES) =====
  218.  
  219.     .DATA?
  220.  
  221. SCREEN_WIDTH    DW    0        ; Width of a line in Bytes
  222. SCREEN_HEIGHT    DW    0        ; Vertical Height in Pixels
  223.  
  224. LAST_PAGE        DW    0        ; # of Display Pages
  225. PAGE_ADDR        DW  4 DUP (0)    ; Offsets to start of each page
  226.  
  227. PAGE_SIZE        DW    0        ; Size of Page in Addr Bytes
  228.  
  229. DISPLAY_PAGE    DW  0        ; Page # currently displayed
  230. ACTIVE_PAGE        DW    0        ; Page # currently active
  231.  
  232. CURRENT_PAGE    DW    0        ; Offset of current Page
  233. CURRENT_SEGMENT    DW    0        ; Segment of VGA memory
  234.  
  235. CURRENT_XOFFSET    DW    0        ; Current Display X Offset
  236. CURRENT_YOFFSET    DW     0        ; Current Display Y Offset
  237.  
  238. CURRENT_MOFFSET    DW    0        ; Current Start Offset
  239.  
  240. MAX_XOFFSET        DW    0        ; Current Display X Offset
  241. MAX_YOFFSET        DW     0        ; Current Display Y Offset
  242.  
  243. CHARSET_LOW        DW    0, 0    ; Far Ptr to Char Set: 0-127
  244. CHARSET_HI        DW    0, 0    ; Far Ptr to Char Set: 128-255
  245.  
  246.     .CODE
  247.  
  248.     ; ===== DATA TABLES =====
  249.  
  250.     ; Data Tables, Put in Code Segment for Easy Access
  251.     ; (Like when all the other Segment Registers are in
  252.     ; use!!) and reduced DGROUP requirements...
  253.  
  254.     ; Bit Mask Tables for Left/Right/Character Masks
  255.  
  256. Left_Clip_Mask        DB    0FH, 0EH, 0CH, 08H
  257.  
  258. Right_Clip_Mask        DB    01H, 03H, 07H, 0FH
  259.  
  260.     ; Bit Patterns for converting character fonts
  261.  
  262. Char_Plane_Data        DB    00H,08H,04H,0CH,02H,0AH,06H,0EH
  263.                        DB    01H,09H,05H,0DH,03H,0BH,07H,0FH
  264.  
  265.         ; CRTC Register Values for Various Configurations
  266.  
  267. MODE_Single_Line:        ; CRTC Setup Data for 400/480 Line modes
  268.         DW    04009H        ; Cell Height (1 Scan Line)
  269.         DW    00014H        ; Dword Mode off
  270.         DW    0E317H        ; turn on Byte Mode
  271.         DW    nil            ; End of CRTC Data for 400/480 Line Mode
  272.  
  273. MODE_Double_Line:        ; CRTC Setup Data for 200/240 Line modes
  274.         DW    04109H        ; Cell Height (2 Scan Lines)
  275.         DW    00014H        ; Dword Mode off
  276.         DW    0E317H        ; turn on Byte Mode
  277.         DW    nil            ; End of CRTC Data for 200/240 Line Mode
  278.  
  279. MODE_320_Wide:            ; CRTC Setup Data for 320 Horz Pixels
  280.         DW    05F00H        ; Horz total
  281.         DW    04F01H        ; Horz Displayed
  282.         DW    05002H        ; Start Horz Blanking
  283.         DW    08203H        ; End Horz Blanking
  284.         DW    05404H        ; Start H Sync
  285.         DW    08005H        ; End H Sync
  286.         DW    nil            ; End of CRTC Data for 320 Horz pixels
  287.  
  288. MODE_360_Wide:            ; CRTC Setup Data for 360 Horz Pixels
  289.         DW    06B00H        ; Horz total
  290.         DW    05901H        ; Horz Displayed
  291.         DW    05A02H        ; Start Horz Blanking
  292.         DW    08E03H        ; End Horz Blanking
  293.         DW    05E04H        ; Start H Sync
  294.         DW    08A05H        ; End H Sync
  295.         DW    nil            ; End of CRTC Data for 360 Horz pixels
  296.  
  297. MODE_200_Tall:
  298. MODE_400_Tall:            ; CRTC Setup Data for 200/400 Line modes
  299.         DW    0BF06H        ; Vertical Total
  300.         DW    01F07H        ; Overflow
  301.         DW    09C10H        ; V Sync Start
  302.         DW    08E11H        ; V Sync End/Prot Cr0 Cr7
  303.         DW    08F12H        ; Vertical Displayed
  304.         DW    09615H        ; V Blank Start
  305.         DW    0B916H        ; V Blank End
  306.         DW    nil            ; End of CRTC Data for 200/400 Lines
  307.  
  308. MODE_240_Tall:
  309. MODE_480_Tall:            ; CRTC Setup Data for 240/480 Line modes
  310.         DW    00D06H        ; Vertical Total
  311.         DW    03E07H        ; Overflow
  312.         DW    0EA10H        ; V Sync Start
  313.         DW    08C11H        ; V Sync End/Prot Cr0 Cr7
  314.         DW    0DF12H        ; Vertical Displayed
  315.         DW    0E715H        ; V Blank Start
  316.         DW    00616H        ; V Blank End
  317.         DW    nil            ; End of CRTC Data for 240/480 Lines
  318.  
  319.         ; Table of Display Mode Tables
  320.  
  321. MODE_TABLE:
  322.         DW    o MODE_320x200, o MODE_320x400
  323.         DW    o MODE_360x200, o MODE_360x400
  324.         DW    o MODE_320x240, o MODE_320x480
  325.         DW    o MODE_360x240, o MODE_360x480
  326.  
  327.         ; Table of Display Mode Components
  328.  
  329. MODE_320x200:            ; Data for 320 by 200 Pixels
  330.  
  331.         DB    063h        ; 400 scan Lines & 25 Mhz Clock
  332.         DB    4            ; Maximum of 4 Pages
  333.         DW    320, 200    ; Displayed Pixels (X,Y)
  334.         DW    1302, 816    ; Max Possible X and Y Sizes
  335.  
  336.         DW    o MODE_320_Wide, o MODE_200_Tall
  337.         DW  o MODE_Double_Line, nil
  338.  
  339. MODE_320x400:            ; Data for 320 by 400 Pixels
  340.  
  341.         DB    063h        ; 400 scan Lines & 25 Mhz Clock
  342.         DB    2            ; Maximum of 2 Pages
  343.         DW    320, 400    ; Displayed Pixels X,Y
  344.         DW    648, 816    ; Max Possible X and Y Sizes
  345.  
  346.         DW    o MODE_320_Wide, o MODE_400_Tall
  347.         DW  o MODE_Single_Line, nil
  348.  
  349. MODE_360x240:            ; Data for 360 by 240 Pixels
  350.  
  351.         DB    0E7h        ; 480 scan Lines & 28 Mhz Clock
  352.         DB    3            ; Maximum of 3 Pages
  353.         DW    360, 240    ; Displayed Pixels X,Y
  354.         DW    1092, 728    ; Max Possible X and Y Sizes
  355.  
  356.         DW    o MODE_360_Wide, o MODE_240_Tall
  357.         DW  o MODE_Double_Line , nil
  358.  
  359. MODE_360x480:            ; Data for 360 by 480 Pixels
  360.  
  361.         DB    0E7h        ; 480 scan Lines & 28 Mhz Clock
  362.         DB    1            ; Only 1 Page Possible
  363.         DW    360, 480    ; Displayed Pixels X,Y
  364.         DW    544, 728    ; Max Possible X and Y Sizes
  365.  
  366.         DW    o MODE_360_Wide, o MODE_480_Tall
  367.         DW  o MODE_Single_Line , nil
  368.  
  369. MODE_320x240:            ; Data for 320 by 240 Pixels
  370.  
  371.         DB    0E3h        ; 480 scan Lines & 25 Mhz Clock
  372.         DB    3            ; Maximum of 3 Pages
  373.         DW    320, 240    ; Displayed Pixels X,Y
  374.         DW    1088, 818    ; Max Possible X and Y Sizes
  375.  
  376.         DW     o MODE_320_Wide, o MODE_240_Tall
  377.         DW  o MODE_Double_Line, nil
  378.             
  379. MODE_320x480:            ; Data for 320 by 480 Pixels
  380.  
  381.         DB    0E3h        ; 480 scan Lines & 25 Mhz Clock
  382.         DB    1            ; Only 1 Page Possible
  383.         DW    320, 480    ; Displayed Pixels X,Y
  384.         DW    540, 818    ; Max Possible X and Y Sizes
  385.     
  386.         DW     o MODE_320_WIDE, o MODE_480_Tall
  387.         DW    o MODE_Single_Line, nil
  388.  
  389. MODE_360x200:            ; Data for 360 by 200 Pixels
  390.  
  391.         DB    067h        ; 400 scan Lines & 28 Mhz Clock
  392.         DB    3            ; Maximum of 3 Pages
  393.         DW    360, 200    ; Displayed Pixels (X,Y)
  394.         DW    1302, 728    ; Max Possible X and Y Sizes
  395.     
  396.         DW     o MODE_360_Wide, MODE_200_Tall
  397.         DW    o MODE_Double_Line, nil
  398.  
  399. MODE_360x400:            ; Data for 360 by 400 Pixels
  400.  
  401.         DB    067h        ; 400 scan Lines & 28 Mhz Clock
  402.         DB    1            ; Maximum of 1 Pages
  403.         DW    360, 400    ; Displayed Pixels X,Y
  404.         DW    648, 816    ; Max Possible X and Y Sizes
  405.     
  406.         DW     o MODE_360_Wide, MODE_400_Tall
  407.         DW    o MODE_Single_Line, nil
  408.  
  409.  
  410.     ; ===== MODE X SETUP ROUTINES =====
  411.  
  412. ;======================================================
  413. ;SET_VGA_MODEX% (ModeType%, MaxXPos%, MaxYpos%, Pages%)
  414. ;======================================================
  415. ;
  416. ; Sets Up the specified version of Mode X.  Allows for
  417. ; the setup of multiple video pages, and a virtual
  418. ; screen which can be larger than the displayed screen
  419. ; (which can then be scrolled a pixel at a time)
  420. ;
  421. ; ENTRY: ModeType = Desired Screen Resolution (0-7)
  422. ;     0 =  320 x 200, 4 Pages max,   1.2:1 Aspect Ratio
  423. ;     1 =  320 x 400, 2 Pages max,   2.4:1 Aspect Ratio
  424. ;     2 =  360 x 200, 3 Pages max,  1.35:1 Aspect Ratio
  425. ;     3 =  360 x 400, 1 Page  max,   2.7:1 Aspect Ratio
  426. ;     4 =  320 x 240, 3 Pages max,     1:1 Aspect Ratio
  427. ;     5 =  320 x 480, 1 Page  max,     2:1 Aspect Ratio
  428. ;     6 =  360 x 240, 3 Pages max, 1.125:1 Aspect Ratio
  429. ;     7 =  360 x 480, 1 Page  max,  2.25:1 Aspect Ratio
  430. ;
  431. ;          MaxXpos = The Desired Virtual Screen Width
  432. ;        MaxYpos = The Desired Virtual Screen Height
  433. ;        Pages   = The Desired # of Video Pages
  434. ;
  435. ; EXIT:  AX = Success Flag:   0 = Failure / -1= Success
  436. ;
  437.  
  438. SVM_STACK    STRUC
  439.     SVM_Table    DW    ?    ; Offset of Mode Info Table
  440.                 DW    ?x4    ; DI, SI, DS, BP
  441.                 DD    ?    ; Caller
  442.     SVM_Pages    DW    ?    ; # of Screen Pages desired
  443.     SVM_Ysize    DW    ?    ; Vertical Screen Size Desired
  444.     SVM_Xsize    DW    ?    ; Horizontal Screen Size Desired
  445.     SVM_Mode    DW    ?    ; Display Resolution Desired
  446. SVM_STACK    ENDS
  447.  
  448.     PUBLIC    SET_VGA_MODEX
  449.  
  450. SET_VGA_MODEX    PROC    FAR
  451.  
  452.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  453.     SUB        SP, 2                ; Allocate workspace
  454.     MOV        BP, SP                ; Set up Stack Frame
  455.  
  456.     ; Check Legality of Mode Request....
  457.     
  458.     MOV        BX, [BP].SVM_Mode    ; Get Requested Mode #
  459.     CMP        BX, NUM_MODES        ; Is it 0..7?
  460.     JAE        @SVM_BadModeSetup    ; If Not, Error out
  461.  
  462.     SHL        BX, 1                      ; Scale BX
  463.     MOV        SI, w MODE_TABLE[BX]    ; CS:SI -> Mode Info
  464.     MOV        [BP].SVM_Table, SI        ; Save ptr for later use
  465.  
  466.     ; Check # of Requested Display Pages
  467.  
  468.     MOV        CX, [BP].SVM_Pages    ; Get # of Requested Pages
  469.     CLR        CH                    ; Set Hi Word = 0!
  470.     CMP        CL, CS:[SI].M_Pages    ; Check # Pages for mode
  471.     JA        @SVM_BadModeSetup    ; Report Error if too Many Pages
  472.     JCXZ    @SVM_BadModeSetup    ; Report Error if 0 Pages
  473.  
  474.     ; Check Validity of X Size
  475.  
  476.     AND        [BP].SVM_XSize, 0FFF8h    ; X size Mod 8 Must = 0
  477.  
  478.     MOV        AX, [BP].SVM_XSize    ; Get Logical Screen Width
  479.     CMP        AX, CS:[SI].M_XSize    ; Check against Displayed X
  480.     JB        @SVM_BadModeSetup    ; Report Error if too small
  481.     CMP        AX, CS:[SI].M_XMax    ; Check against Max X
  482.     JA        @SVM_BadModeSetup    ; Report Error if too big
  483.     
  484.     ; Check Validity of Y Size
  485.  
  486.     MOV        BX, [BP].SVM_YSize    ; Get Logical Screen Height
  487.     CMP        BX, CS:[SI].M_YSize    ; Check against Displayed Y
  488.     JB        @SVM_BadModeSetup    ; Report Error if too small
  489.     CMP        BX, CS:[SI].M_YMax    ; Check against Max Y
  490.     JA        @SVM_BadModeSetup    ; Report Error if too big
  491.     
  492.     ; Enough memory to Fit it all?    
  493.  
  494.     SHR        AX, 2                ; # of Bytes:Line = XSize/4
  495.     MUL        CX                    ; AX = Bytes/Line * Pages
  496.     MUL        BX                    ; DX:AX = Total VGA mem needed
  497.     JNO        @SVM_Continue        ; Exit if Total Size > 256K
  498.  
  499.     DEC        DX                    ; Was it Exactly 256K???
  500.     OR        DX, AX                ; (DX = 1, AX = 0000)
  501.     JZ        @SVM_Continue        ; if so, it's valid...
  502.  
  503. @SVM_BadModeSetup:
  504.  
  505.     CLR        AX                    ; Return Value = False
  506.     JMP        @SVM_Exit            ; Normal Exit
  507.     
  508. @SVM_Continue:
  509.  
  510.     MOV        AX, 13H                ; Start with Mode 13H
  511.     INT        10H                    ; Let BIOS Set Mode
  512.  
  513.     OUT_16    SC_INDEX, CHAIN4_OFF            ; Disable Chain 4 Mode
  514.     OUT_16    SC_INDEX, ASYNC_RESET            ; (A)synchronous Reset
  515.     OUT_8    MISC_OUTPUT, CS:[SI].M_MiscR    ; Set New Timing/Size
  516.     OUT_16    SC_INDEX, SEQU_RESTART            ; Restart Sequencer ...
  517.  
  518.     OUT_8    CRTC_INDEX, 11H        ; Select Vert Retrace End Register
  519.     INC        DX                    ; Point to Data
  520.     IN        AL, DX                ; Get Value, Bit 7 = Protect
  521.     AND        AL, 7FH                ; Mask out Write Protect
  522.     OUT        DX, AL                ; And send it back
  523.  
  524.     MOV        DX, CRTC_INDEX        ; Vga Crtc Registers
  525.     ADD        SI, M_CRTC            ; SI -> CRTC Parameter Data
  526.  
  527.     ; Load Tables of CRTC Parameters from List of Tables
  528.  
  529. @SVM_Setup_Table:
  530.  
  531.     MOV        DI, CS:[SI]            ; Get Pointer to CRTC Data Tbl
  532.     ADD        SI, 2                ; Point to next Ptr Entry
  533.     OR        DI, DI                ; A nil Ptr means that we have
  534.     JZ        @SVM_Set_Data        ; finished CRTC programming
  535.  
  536. @SVM_Setup_CRTC:
  537.     MOV        AX, CS:[DI]            ; Get CRTC Data from Table
  538.     ADD        DI, 2                ; Advance Pointer
  539.     OR        AX, AX                ; At End of Data Table?
  540.     JZ        @SVM_Setup_Table    ; If so, Exit & get next Table
  541.  
  542.     OUT        DX, AX                ; Reprogram VGA CRTC reg
  543.       JMP        s @SVM_Setup_CRTC    ; Process Next Table Entry
  544.  
  545.     ; Initialize Page & Scroll info, DI = 0
  546.  
  547. @SVM_Set_Data:
  548.     MOV        DISPLAY_PAGE, DI    ; Display Page = 0
  549.     MOV        ACTIVE_PAGE, DI        ; Active Page = 0
  550.     MOV        CURRENT_PAGE, DI    ; Current Page (Offset) = 0
  551.     MOV        CURRENT_XOFFSET, DI    ; Horz Scroll Index = 0
  552.     MOV        CURRENT_YOFFSET, DI    ; Vert Scroll Index = 0
  553.     MOV        CURRENT_MOFFSET, DI    ; Memory Scroll Index = 0
  554.  
  555.     MOV        AX, VGA_SEGMENT        ; Segment for VGA memory
  556.     MOV        CURRENT_SEGMENT, AX    ; Save for Future LES's
  557.       
  558.     ; Set Logical Screen Width, X Scroll and Our Data
  559.  
  560.     MOV        SI, [BP].SVM_Table    ; Get Saved Ptr to Mode Info
  561.     MOV        AX, [BP].SVM_Xsize    ; Get Display Width
  562.  
  563.     MOV        CX, AX                ; CX = Logical Width
  564.     SUB        CX, CS:[SI].M_XSize    ; CX = Max X Scroll Value
  565.     MOV        MAX_XOFFSET, CX        ; Set Maximum X Scroll
  566.  
  567.     SHR        AX, 2                ; Bytes = Pixels / 4
  568.     MOV        SCREEN_WIDTH, AX    ; Save Width in Pixels
  569.  
  570.     SHR        AX, 1                ; Offset Value = Bytes / 2
  571.     MOV        AH, 13h                ; CRTC Offset Register Index
  572.     XCHG    AL, AH                ; Switch format for OUT
  573.     OUT     DX, AX                ; Set VGA CRTC Offset Reg
  574.  
  575.     ; Setup Data table, Y Scroll, Misc for Other Routines
  576.  
  577.     MOV        AX, [BP].SVM_Ysize    ; Get Logical Screen Height
  578.  
  579.     MOV        CX, AX                ; CX = Logical Height
  580.     SUB        BX, CS:[SI].M_YSize    ; CX = Max Y Scroll Value
  581.     MOV        MAX_YOFFSET, CX        ; Set Maximum Y Scroll
  582.  
  583.     MOV        SCREEN_HEIGHT, AX    ; Save Height in Pixels
  584.     MUL        SCREEN_WIDTH        ; AX = Page Size in Bytes,
  585.     MOV        PAGE_SIZE, AX        ; Save Page Size
  586.  
  587.     MOV        CX, [BP].SVM_Pages    ; Get # of Pages
  588.     MOV        LAST_PAGE, CX        ; Save # of Pages
  589.  
  590.     CLR        BX                    ; Page # = 0
  591.     MOV        DX, BX                ; Page 0 Offset = 0
  592.  
  593. @SVM_Set_Pages:
  594.  
  595.     MOV        PAGE_ADDR[BX], DX    ; Set Page #(BX) Offset
  596.     ADD        BX, 2                ; Page#++
  597.     ADD        DX, AX                ; Compute Addr of Next Page
  598.     LOOPx    CX,    @SVM_Set_Pages    ; Loop until all Pages Set
  599.  
  600.     ; Clear VGA Memory 
  601.  
  602.     OUT_16    SC_INDEX, ALL_PLANES_ON    ; Select All Planes
  603.     LES        DI, d CURRENT_PAGE        ; -> Start of VGA memory
  604.  
  605.     CLR        AX                    ; AX = 0 
  606.     CLD                            ; Block Xfer Forwards
  607.     MOV        CX, 8000H            ; 32K * 4 * 2 = 256K
  608.     REP        STOSW                ; Clear dat memory!
  609.  
  610.     ; Setup Font Pointers
  611.  
  612.     MOV        BH, ROM_8x8_Lo        ; Ask for 8x8 Font, 0-127
  613.     MOV        AX, GET_CHAR_PTR    ; Service to Get Pointer
  614.     INT        10h                    ; Call VGA BIOS
  615.  
  616.     MOV        CHARSET_LOW, BP        ; Save Char Set Offset
  617.     MOV        CHARSET_LOW+2, ES    ; Save Char Set Segment
  618.  
  619.     MOV        BH, ROM_8x8_Hi        ; Ask for 8x8 Font, 128-255
  620.     MOV        AX, GET_CHAR_PTR    ; Service to Get Pointer
  621.     INT        10h                    ; Call VGA BIOS
  622.  
  623.     MOV        CHARSET_HI, BP        ; Save Char Set Offset
  624.     MOV        CHARSET_HI+2, ES    ; Save Char Set Segment
  625.  
  626.     MOV        AX, True            ; Return Success Code
  627.  
  628. @SVM_EXIT:
  629.     ADD        SP, 2                ; Deallocate workspace
  630.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  631.     RET        8                    ; Exit & Clean Up Stack
  632.  
  633. SET_VGA_MODEX    ENDP
  634.  
  635.  
  636. ;==================
  637. ;SET_MODEX% (Mode%)
  638. ;==================
  639. ;
  640. ; Quickie Mode Set - Sets Up Mode X to Default Configuration
  641. ;
  642. ; ENTRY: ModeType = Desired Screen Resolution (0-7)
  643. ;        (See SET_VGA_MODEX for list)
  644. ; EXIT:  AX = Success Flag:   0 = Failure / -1= Success
  645. ;
  646.  
  647. SM_STACK    STRUC
  648.                 DW    ?    ; BP
  649.                 DD    ?    ; Caller
  650.     SM_Mode        DW    ?    ; Desired Screen Resolution
  651. SM_STACK    ENDS
  652.  
  653.     PUBLIC    SET_MODEX
  654.  
  655. SET_MODEX    PROC    FAR
  656.  
  657.     PUSH    BP                    ; Preserve Important
  658.     MOV        BP, SP                ; Set up Stack Frame
  659.  
  660.     CLR        AX                    ; Assume Failure
  661.     MOV        BX, [BP].SM_Mode    ; Get Desired Mode #
  662.     CMP        BX, NUM_MODES        ; Is it a Valid Mode #?
  663.     JAE        @SMX_Exit            ; If Not, don't Bother
  664.  
  665.     PUSH    BX                    ; Push Mode Parameter
  666.  
  667.     SHL        BX, 1                      ; Scale BX to word Index
  668.     MOV        SI, w MODE_TABLE[BX]    ; CS:SI -> Mode Info
  669.  
  670.     PUSH    CS:[SI].M_XSize        ; Push Default X Size
  671.     PUSH    CS:[SI].M_Ysize        ; Push Default Y size
  672.     MOV        AL, CS:[SI].M_Pages    ; Get Default # of Pages
  673.     CLR        AH                    ; Hi Byte = 0
  674.     PUSH    AX                    ; Push # Pages
  675.  
  676.     CALL    f SET_VGA_MODEX        ; Set up Mode X!
  677.  
  678. @SMX_Exit:
  679.     POP        BP                    ; Restore Register
  680.     RET     2                    ; Exit & Clean Up Stack
  681.  
  682. SET_MODEX    ENDP
  683.  
  684.  
  685.     ; ===== BASIC GRAPHICS PRIMITIVES =====
  686.  
  687. ;============================
  688. ;CLEAR_VGA_SCREEN (ColorNum%)
  689. ;============================
  690. ;
  691. ; Clears the active display page 
  692. ;
  693. ; ENTRY: ColorNum = Color Value to fill the page with
  694. ;
  695. ; EXIT:  No meaningful values returned
  696. ;
  697.  
  698. CVS_STACK    STRUC
  699.                 DW    ?,?    ; DI, BP
  700.                 DD    ?    ; Caller
  701.     CVS_COLOR    DB    ?,?    ; Color to Set Screen to
  702. CVS_STACK    ENDS
  703.  
  704.     PUBLIC    CLEAR_VGA_SCREEN
  705.  
  706. CLEAR_VGA_SCREEN    PROC    FAR
  707.  
  708.     PUSHx    BP, DI                ; Preserve Important Registers
  709.     MOV        BP, SP                ; Set up Stack Frame
  710.  
  711.     OUT_16    SC_INDEX, ALL_PLANES_ON    ; Select All Planes
  712.     LES        DI, d CURRENT_PAGE        ; Point to Active VGA Page
  713.  
  714.     MOV        AL, [BP].CVS_COLOR    ; Get Color
  715.     MOV        AH, AL                ; Copy for Word Write
  716.     CLD                            ; Block fill Forwards
  717.  
  718.     MOV        CX, PAGE_SIZE        ; Get Size of Page
  719.     SHR        CX, 1                ; Divide by 2 for Words
  720.     REP        STOSW                ; Block Fill VGA memory
  721.  
  722.     POPx    DI, BP                ; Restore Saved Registers
  723.     RET     2                    ; Exit & Clean Up Stack
  724.  
  725. CLEAR_VGA_SCREEN    ENDP
  726.  
  727.  
  728. ;===================================
  729. ;SET_POINT (Xpos%, Ypos%, ColorNum%)
  730. ;===================================
  731. ;
  732. ; Plots a single Pixel on the active display page
  733. ;
  734. ; ENTRY: Xpos     = X position to plot pixel at
  735. ;        Ypos     = Y position to plot pixel at
  736. ;        ColorNum = Color to plot pixel with
  737. ;
  738. ; EXIT:  No meaningful values returned
  739. ;
  740.  
  741. SP_STACK    STRUC
  742.                 DW    ?    ; BP
  743.                 DD    ?    ; Caller
  744.     SETP_Color    DB    ?,? ; Color of Point to Plot
  745.     SETP_Ypos    DW    ?    ; Y pos of Point to Plot
  746.     SETP_Xpos    DW    ?    ; X pos of Point to Plot
  747. SP_STACK    ENDS
  748.  
  749.         PUBLIC SET_POINT
  750.  
  751. SET_POINT    PROC    FAR
  752.  
  753.     PUSH    BP                    ; Preserve Registers
  754.     MOV        BP, SP                ; Set up Stack Frame
  755.  
  756.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  757.  
  758.     MOV        AX, [BP].SETP_Ypos    ; Get Line # of Pixel
  759.     MUL        SCREEN_WIDTH           ; Get Offset to Start of Line
  760.  
  761.     MOV     BX, [BP].SETP_Xpos  ; Get Xpos
  762.     MOV        CX, BX                ; Copy to extract Plane # from
  763.     SHR        BX, 2                ; X offset (Bytes) = Xpos/4
  764.     ADD     BX, AX              ; Offset = Width*Ypos + Xpos/4
  765.  
  766.     MOV        AX, MAP_MASK_PLANE1    ; Map Mask & Plane Select Register
  767.     AND     CL, PLANE_BITS        ; Get Plane Bits
  768.     SHL        AH, CL                ; Get Plane Select Value
  769.     OUT_16    SC_Index, AX        ; Select Plane
  770.  
  771.     MOV     AL,[BP].SETP_Color    ; Get Pixel Color
  772.     MOV        ES:[DI+BX], AL        ; Draw Pixel
  773.  
  774.     POP        BP                    ; Restore Saved Registers
  775.     RET     6                   ; Exit and Clean up Stack
  776.  
  777. SET_POINT        ENDP
  778.  
  779.  
  780. ;==========================
  781. ;READ_POINT% (Xpos%, Ypos%)
  782. ;==========================
  783. ;
  784. ; Read the color of a pixel from the Active Display Page
  785. ;
  786. ; ENTRY: Xpos = X position of pixel to read
  787. ;        Ypos = Y position of pixel to read
  788. ;              
  789. ; EXIT:  AX   = Color of Pixel at (Xpos, Ypos)
  790. ;
  791.  
  792. RP_STACK    STRUC
  793.             DW    ?    ; BP
  794.             DD    ?    ; Caller
  795.     RP_Ypos    DW    ?    ; Y pos of Point to Read
  796.     RP_Xpos    DW    ?    ; X pos of Point to Read
  797. RP_STACK    ENDS
  798.  
  799.         PUBLIC    READ_POINT
  800.  
  801. READ_POINT        PROC    FAR
  802.  
  803.     PUSH    BP                    ; Preserve Registers
  804.     MOV        BP, SP                ; Set up Stack Frame
  805.  
  806.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  807.  
  808.     MOV        AX, [BP].RP_Ypos    ; Get Line # of Pixel
  809.     MUL        SCREEN_WIDTH           ; Get Offset to Start of Line
  810.  
  811.     MOV     BX, [BP].RP_Xpos       ; Get Xpos
  812.     MOV        CX, BX
  813.     SHR        BX, 2                ; X offset (Bytes) = Xpos/4
  814.     ADD     BX, AX              ; Offset = Width*Ypos + Xpos/4
  815.  
  816.     MOV        AL, READ_MAP        ; GC Read Mask Register
  817.     MOV        AH, CL                ; Get Xpos
  818.     AND     AH, PLANE_BITS        ; & mask out Plane #
  819.     OUT_16    GC_INDEX, AX        ; Select Plane to read in
  820.  
  821.     CLR        AH                    ; Clear Return Value Hi byte
  822.     MOV        AL, ES:[DI+BX]        ; Get Color of Pixel
  823.  
  824.     POP        BP                    ; Restore Saved Registers
  825.     RET     4                   ; Exit and Clean up Stack
  826.  
  827. READ_POINT        ENDP
  828.  
  829.  
  830. ;======================================================
  831. ;FILL_BLOCK (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
  832. ;======================================================
  833. ;
  834. ; Fills a rectangular block on the active display Page
  835. ;
  836. ; ENTRY: Xpos1    = Left X position of area to fill
  837. ;        Ypos1    = Top Y position of area to fill
  838. ;        Xpos2    = Right X position of area to fill
  839. ;        Ypos2    = Bottom Y position of area to fill
  840. ;        ColorNum = Color to fill area with
  841. ;
  842. ; EXIT:  No meaningful values returned
  843. ;
  844.  
  845. FB_STACK    STRUC
  846.                 DW    ?x4    ; DS, DI, SI, BP
  847.                 DD    ?    ; Caller
  848.     FB_Color    DB    ?,? ; Fill Color
  849.     FB_Ypos2    DW    ?    ; Y pos of Lower Right Pixel
  850.     FB_Xpos2    DW    ?    ; X pos of Lower Right Pixel
  851.     FB_Ypos1    DW    ?    ; Y pos of Upper Left Pixel
  852.     FB_Xpos1    DW    ?    ; X pos of Upper Left Pixel
  853. FB_STACK    ENDS
  854.         
  855.         PUBLIC    FILL_BLOCK
  856.  
  857. FILL_BLOCK    PROC    FAR
  858.  
  859.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  860.     MOV        BP, SP                ; Set up Stack Frame
  861.  
  862.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  863.     CLD                            ; Direction Flag = Forward
  864.  
  865.     OUT_8    SC_INDEX, MAP_MASK    ; Set up for Plane Select
  866.  
  867.     ; Validate Pixel Coordinates
  868.     ; If necessary, Swap so X1 <= X2, Y1 <= Y2
  869.  
  870.     MOV     AX, [BP].FB_Ypos1   ; AX = Y1   is Y1< Y2?
  871.     MOV     BX, [BP].FB_Ypos2   ; BX = Y2
  872.     CMP     AX, BX
  873.     JLE     @FB_NOSWAP1
  874.  
  875.     MOV     [BP].FB_Ypos1, BX   ; Swap Y1 and Y2 and save Y1
  876.     XCHG    AX, BX                ; on stack for future use
  877.  
  878. @FB_NOSWAP1:
  879.     SUB     BX, AX              ; Get Y width
  880.     INC     BX                    ; Add 1 to avoid 0 value
  881.     MOV     [BP].FB_Ypos2, BX   ; Save in Ypos2
  882.  
  883.     MUL        SCREEN_WIDTH        ; Mul Y1 by Bytes per Line
  884.     ADD        DI, AX                ; DI = Start of Line Y1
  885.  
  886.     MOV     AX, [BP].FB_Xpos1   ; Check X1 <= X2
  887.     MOV     BX, [BP].FB_Xpos2   ;
  888.     CMP     AX, BX
  889.     JLE     @FB_NOSWAP2            ; Skip Ahead if Ok
  890.  
  891.     MOV     [BP].FB_Xpos2, AX    ; Swap X1 AND X2 and save X2
  892.     XCHG    AX, BX                ; on stack for future use
  893.  
  894.     ; All our Input Values are in order, Now determine
  895.     ; How many full "bands" 4 pixels wide (aligned) there
  896.     ; are, and if there are partial bands (<4 pixels) on
  897.     ; the left and right edges.
  898.  
  899. @FB_NOSWAP2:
  900.     MOV        DX, AX                ; DX = X1 (Pixel Position)
  901.     SHR        DX, 2                ; DX/4 = Bytes into Line
  902.     ADD        DI, DX                ; DI = Addr of Upper-Left Corner
  903.  
  904.     MOV        CX, BX                ; CX = X2 (Pixel Position)
  905.     SHR        CX, 2                ; CX/4 = Bytes into Line
  906.  
  907.     CMP        DX, CX                ; Start and end in same band?
  908.     JNE        @FB_NORMAL            ; if not, check for l & r edges
  909.     JMP        @FB_ONE_BAND_ONLY    ; if so, then special processing
  910.  
  911. @FB_NORMAL:
  912.     SUB        CX, DX                ; CX = # bands -1    
  913.     MOV        SI, AX                ; SI = PLANE#(X1)
  914.     AND        SI, PLANE_BITS        ; if Left edge is aligned then
  915.     JZ        @FB_L_PLANE_FLUSH    ; no special processing..
  916.  
  917.     ; Draw "Left Edge" vertical strip of 1-3 pixels...
  918.  
  919.     OUT_8    SC_Data, Left_Clip_Mask[SI]    ; Set Left Edge Plane Mask 
  920.  
  921.     MOV        SI, DI                ; SI = Copy of Start Addr (UL)
  922.  
  923.     MOV        DX, [BP].FB_Ypos2    ; Get # of Lines to draw
  924.     MOV        AL, [BP].FB_Color    ; Get Fill Color
  925.     MOV        BX, SCREEN_WIDTH    ; Get Vertical increment Value
  926.  
  927. @FB_LEFT_LOOP:
  928.     MOV        ES:[SI], AL            ; Fill in Left Edge Pixels
  929.     ADD        SI, BX                ; Point to Next Line (Below)
  930.     LOOPjz    DX, @FB_LEFT_CONT    ; Exit loop if all Lines Drawn
  931.  
  932.     MOV        ES:[SI], AL            ; Fill in Left Edge Pixels
  933.     ADD        SI, BX                ; Point to Next Line (Below)
  934.     LOOPx    DX, @FB_LEFT_LOOP    ; loop until left strip is drawn
  935.     
  936. @FB_LEFT_CONT:
  937.         
  938.     INC        DI                    ; Point to Middle (or Right) Block
  939.     DEC        CX                    ; Reset CX instead of JMP @FB_RIGHT
  940.  
  941. @FB_L_PLANE_FLUSH:    
  942.     INC        CX                    ; Add in Left band to middle block
  943.     
  944.     ; DI = Addr of 1st middle Pixel (band) to fill
  945.     ; CX = # of Bands to fill -1
  946.  
  947. @FB_RIGHT:                
  948.     MOV        SI, [BP].FB_Xpos2    ; Get Xpos2
  949.     AND        SI, PLANE_BITS        ; Get Plane values
  950.     CMP        SI, 0003            ; Plane = 3?
  951.     JE        @FB_R_EDGE_FLUSH    ; Hey, add to middle
  952.  
  953.     ; Draw "Right Edge" vertical strip of 1-3 pixels...
  954.  
  955.     OUT_8    SC_Data, Right_Clip_Mask[SI]    ; Right Edge Plane Mask
  956.                 
  957.     MOV        SI, DI                ; Get Addr of Left Edge
  958.     ADD        SI, CX                ; Add Width-1 (Bands)
  959.     DEC        SI                    ; To point to top of Right Edge
  960.  
  961.     MOV        DX, [BP].FB_Ypos2    ; Get # of Lines to draw
  962.     MOV        AL, [BP].FB_Color    ; Get Fill Color
  963.     MOV        BX, SCREEN_WIDTH    ; Get Vertical increment Value
  964.  
  965. @FB_RIGHT_LOOP:
  966.     MOV        ES:[SI], AL            ; Fill in Right Edge Pixels
  967.     ADD        SI, BX                ; Point to Next Line (Below)
  968.     LOOPjz    DX,    @FB_RIGHT_CONT    ; Exit loop if all Lines Drawn
  969.  
  970.     MOV        ES:[SI], AL            ; Fill in Right Edge Pixels
  971.     ADD        SI, BX                ; Point to Next Line (Below)
  972.     LOOPx    DX,    @FB_RIGHT_LOOP    ; loop until left strip is drawn
  973.  
  974. @FB_RIGHT_CONT:
  975.     
  976.     DEC        CX                    ; Minus 1 for Middle bands
  977.     JZ        @FB_EXIT            ; Uh.. no Middle bands...
  978.  
  979. @FB_R_EDGE_FLUSH:    
  980.  
  981.     ; DI = Addr of Upper Left block to fill 
  982.     ; CX = # of Bands to fill in (width)
  983.  
  984.     OUT_8    SC_Data, ALL_PLANES    ; Write to All Planes
  985.  
  986.     MOV        DX, SCREEN_WIDTH    ; DX = DI Increment
  987.     SUB        DX, CX                ;  = Screen_Width-# Planes Filled
  988.     
  989.     MOV        BX, CX                ; BX = Quick Refill for CX
  990.     MOV        SI, [BP].FB_Ypos2    ; SI = # of Line to Fill
  991.     MOV        AL, [BP].FB_Color    ; Get Fill Color
  992.  
  993. @FB_MIDDLE_LOOP:
  994.     REP        STOSB                ; Fill in entire line
  995.  
  996.     MOV        CX, BX                ; Recharge CX (Line Width)
  997.     ADD        DI, DX                ; Point to start of Next Line
  998.     LOOPx    SI, @FB_MIDDLE_LOOP    ; Loop until all lines drawn
  999.                                                            
  1000.     JMP        s @FB_EXIT            ; Outa here
  1001.  
  1002. @FB_ONE_BAND_ONLY:
  1003.     MOV        SI, AX                    ; Get Left Clip Mask, Save X1
  1004.     AND        SI, PLANE_BITS            ; Mask out Row #    
  1005.     MOV        AL, Left_Clip_Mask[SI]    ; Get Left Edge Mask
  1006.     MOV        SI, BX                      ; Get Right Clip Mask, Save X2
  1007.     AND        SI, PLANE_BITS            ; Mask out Row #
  1008.     AND        AL, Right_Clip_Mask[SI]    ; Get Right Edge Mask byte
  1009.  
  1010.     OUT_8    SC_Data, AL            ; Clip For Left & Right Masks
  1011.  
  1012.     MOV        CX, [BP].FB_Ypos2    ; Get # of Lines to draw
  1013.     MOV        AL, [BP].FB_Color    ; Get Fill Color
  1014.     MOV        BX, SCREEN_WIDTH    ; Get Vertical increment Value
  1015.  
  1016. @FB_ONE_LOOP:
  1017.     MOV        ES:[DI], AL            ; Fill in Pixels
  1018.     ADD        DI, BX                ; Point to Next Line (Below)
  1019.     LOOPjz    CX,    @FB_EXIT        ; Exit loop if all Lines Drawn
  1020.  
  1021.     MOV        ES:[DI], AL            ; Fill in Pixels
  1022.     ADD        DI, BX                ; Point to Next Line (Below)
  1023.     LOOPx    CX,    @FB_ONE_LOOP    ; loop until left strip is drawn
  1024.  
  1025. @FB_EXIT:
  1026.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  1027.     RET     10                  ; Exit and Clean up Stack
  1028.  
  1029. FILL_BLOCK   ENDP
  1030.  
  1031.  
  1032. ;=====================================================
  1033. ;DRAW_LINE (Xpos1%, Ypos1%, Xpos2%, Ypos2%, ColorNum%)
  1034. ;=====================================================
  1035. ;
  1036. ; Draws a Line on the active display page
  1037. ;
  1038. ; ENTRY: Xpos1    = X position of first point on line
  1039. ;        Ypos1    = Y position of first point on line
  1040. ;        Xpos2    = X position of last point on line
  1041. ;        Ypos2    = Y position of last point on line
  1042. ;        ColorNum = Color to draw line with
  1043. ;
  1044. ; EXIT:  No meaningful values returned
  1045. ;
  1046.  
  1047. DL_STACK    STRUC
  1048.                 DW    ?x3    ; DI, SI, BP
  1049.                 DD    ?    ; Caller
  1050.     DL_ColorF    DB    ?,?    ; Line Draw Color
  1051.     DL_Ypos2    DW    ?    ; Y pos of last point
  1052.     DL_Xpos2    DW    ?    ; X pos of last point
  1053.     DL_Ypos1    DW    ?    ; Y pos of first point
  1054.     DL_Xpos1    DW    ?    ; X pos of first point
  1055. DL_STACK    ENDS
  1056.  
  1057.         PUBLIC DRAW_LINE
  1058.  
  1059. DRAW_LINE    PROC    FAR
  1060.  
  1061.     PUSHx    BP, SI, DI            ; Preserve Important Registers
  1062.     MOV        BP, SP                ; Set up Stack Frame
  1063.     CLD                            ; Direction Flag = Forward
  1064.  
  1065.     OUT_8    SC_INDEX, MAP_MASK    ; Set up for Plane Select
  1066.     MOV     CH, [BP].DL_ColorF  ; Save Line Color in CH
  1067.  
  1068.     ; Check Line Type
  1069.  
  1070.     MOV     SI, [BP].DL_Xpos1   ; AX = X1   is X1< X2?
  1071.     MOV     DI, [BP].DL_Xpos2   ; DX = X2
  1072.     CMP     SI, DI                ; Is X1 < X2
  1073.     JE      @DL_VLINE             ; If X1=X2, Draw Vertical Line
  1074.     JL      @DL_NOSWAP1            ; If X1 < X2, don't swap
  1075.  
  1076.     XCHG    SI, DI              ; X2 IS > X1, SO SWAP THEM
  1077.  
  1078. @DL_NOSWAP1:
  1079.  
  1080.     ; SI = X1, DI = X2
  1081.  
  1082.     MOV     AX, [BP].DL_Ypos1   ; AX = Y1   is Y1 <> Y2?
  1083.     CMP     AX, [BP].DL_Ypos2    ; Y1 = Y2?
  1084.     JE        @DL_HORZ            ; If so, Draw a Horizontal Line
  1085.  
  1086.     JMP        @DL_BREZHAM            ; Diagonal line... go do it...
  1087.  
  1088.     ; This Code draws a Horizontal Line in Mode X where:
  1089.     ; SI = X1, DI = X2, and AX = Y1/Y2
  1090.  
  1091. @DL_HORZ:
  1092.  
  1093.     MUL        SCREEN_WIDTH        ; Offset = Ypos * Screen_Width
  1094.     MOV        DX, AX                ; CX = Line offset into Page
  1095.  
  1096.     MOV        AX, SI                    ; Get Left edge, Save X1
  1097.     AND        SI, PLANE_BITS            ; Mask out Row #    
  1098.     MOV        BL, Left_Clip_Mask[SI]    ; Get Left Edge Mask
  1099.     MOV        CX, DI                    ; Get Right edge, Save X2
  1100.     AND        DI, PLANE_BITS            ; Mask out Row #
  1101.     MOV        BH, Right_Clip_Mask[DI]    ; Get Right Edge Mask byte
  1102.  
  1103.     SHR        AX, 2                ; Get X1 Byte # (=X1/4)
  1104.     SHR        CX, 2                ; Get X2 Byte # (=X2/4)
  1105.  
  1106.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  1107.     ADD        DI, DX                ; Point to Start of Line
  1108.     ADD        DI, AX                ; Point to Pixel X1
  1109.  
  1110.     SUB        CX, AX                ; CX = # Of Bands (-1) to set
  1111.     JNZ        @DL_LONGLN            ; jump if longer than one segment
  1112.  
  1113.     AND        BL, BH                ; otherwise, merge clip masks    
  1114.  
  1115. @DL_LONGLN:
  1116.  
  1117.     OUT_8    SC_Data, BL            ; Set the Left Clip Mask
  1118.  
  1119.     MOV     AL, [BP].DL_ColorF  ; Get Line Color
  1120.     MOV        BL, AL                ; BL = Copy of Line Color
  1121.     STOSB                        ; Set Left (1-4) Pixels
  1122.  
  1123.     JCXZ    @DL_EXIT            ; Done if only one Line Segment
  1124.  
  1125.     DEC        CX                    ; CX = # of Middle Segments
  1126.     JZ        @DL_XRSEG            ; If no middle segments....
  1127.  
  1128.     ; Draw Middle Segments
  1129.  
  1130.     OUT_8    DX, ALL_PLANES        ; Write to ALL Planes
  1131.  
  1132.     MOV        AL, BL                ; Get Color from BL
  1133.     REP        STOSB                ; Draw Middle (4 Pixel) Segments
  1134.  
  1135. @DL_XRSEG:
  1136.     OUT_8    DX, BH                ; Select Planes for Right Clip Mask
  1137.     MOV        AL, BL                ; Get Color Value
  1138.     STOSB                        ; Draw Right (1-4) Pixels
  1139.  
  1140.     JMP        s @DL_EXIT            ; We Are Done...
  1141.  
  1142.  
  1143.     ; This Code Draws A Vertical Line.  On entry:
  1144.     ; CH = Line Color, SI & DI = X1
  1145.  
  1146. @DL_VLINE:
  1147.  
  1148.     MOV     AX, [BP].DL_Ypos1   ; AX = Y1 
  1149.     MOV     SI, [BP].DL_Ypos2   ; SI = Y2
  1150.     CMP     AX, SI                ; Is Y1 < Y2?
  1151.     JLE     @DL_NOSWAP2         ; if so, Don't Swap them
  1152.  
  1153.     XCHG    AX, SI              ; Ok, NOW Y1 < Y2
  1154.  
  1155. @DL_NOSWAP2:          
  1156.  
  1157.     SUB     SI, AX              ; SI = Line Height (Y2-Y1+1)
  1158.     INC     SI
  1159.  
  1160.     ; AX = Y1, DI = X1, Get offset into Page into AX
  1161.  
  1162.     MUL        SCREEN_WIDTH        ; Offset = Y1 (AX) * Screen Width
  1163.     MOV        DX, DI                ; Copy Xpos into DX
  1164.     SHR        DI, 2                ; DI = Xpos/4
  1165.     ADD     AX, DI              ; DI = Xpos/4 + ScreenWidth * Y1
  1166.  
  1167.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  1168.     ADD        DI, AX                ; Point to Pixel X1, Y1
  1169.  
  1170.     ;Select Plane
  1171.  
  1172.     MOV        CL, DL                ; CL = Save X1
  1173.     AND        CL, PLANE_BITS        ; Get X1 MOD 4 (Plane #)
  1174.     MOV        AX, MAP_MASK_PLANE1    ; Code to set Plane #1
  1175.     SHL        AH, CL                ; Change to Correct Plane #
  1176.     OUT_16    SC_Index, AX        ; Select Plane
  1177.  
  1178.     MOV     AL, CH              ; Get Saved Color
  1179.     MOV     BX, SCREEN_WIDTH    ; Get Offset to Advance Line By
  1180.  
  1181. @DL_VLoop:
  1182.     MOV     ES:[DI], AL            ; Draw Single Pixel
  1183.     ADD     DI, BX              ; Point to Next Line
  1184.     LOOPjz    SI, @DL_EXIT        ; Lines--, Exit if done
  1185.  
  1186.     MOV     ES:[DI], AL            ; Draw Single Pixel
  1187.     ADD     DI, BX              ; Point to Next Line
  1188.     LOOPx    SI, @DL_VLoop        ; Lines--, Loop until Done
  1189.  
  1190. @DL_EXIT:
  1191.  
  1192.     JMP        @DL_EXIT2            ; Done!
  1193.  
  1194.     ; This code Draws a diagonal line in Mode X
  1195.  
  1196. @DL_BREZHAM:
  1197.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  1198.  
  1199.     MOV     AX, [BP].DL_Ypos1   ; get Y1 value
  1200.     MOV     BX, [BP].DL_Ypos2   ; get Y2 value
  1201.     MOV        CX, [BP].DL_Xpos1    ; Get Starting Xpos
  1202.  
  1203.     CMP        BX, AX                ; Y2-Y1 is?
  1204.     JNC        @DL_DeltaYOK        ; if Y2>=Y1 then goto...
  1205.  
  1206.     XCHG    BX, AX                ; Swap em...
  1207.     MOV        CX, [BP].DL_Xpos2    ; Get New Starting Xpos
  1208.  
  1209. @DL_DeltaYOK:
  1210.     MUL        SCREEN_WIDTH        ; Offset = SCREEN_WIDTH * Y1
  1211.  
  1212.     ADD        DI, AX                ; DI -> Start of Line Y1 on Page
  1213.     MOV        AX, CX                ; AX = Xpos (X1)
  1214.     SHR        AX, 2                ; /4 = Byte Offset into Line
  1215.     ADD        DI, AX                ; DI = Starting pos (X1,Y1)
  1216.  
  1217.     MOV        AL, 11h                ; Staring Mask
  1218.     AND        CL, PLANE_BITS        ; Get Plane #
  1219.     SHL        AL, CL                ; and shift into place
  1220.     MOV        AH, [BP].DL_ColorF    ; Color in Hi Bytes
  1221.  
  1222.     PUSH    AX                    ; Save Mask,Color...
  1223.  
  1224.     MOV        AH, AL                ; Plane # in AH
  1225.     MOV        AL, MAP_MASK        ; Select Plane Register
  1226.      OUT_16    SC_Index, AX        ; Select initial plane
  1227.  
  1228.     MOV     AX, [BP].DL_Xpos1   ; get X1 value
  1229.     MOV     BX, [BP].DL_Ypos1   ; get Y1 value
  1230.     MOV     CX, [BP].DL_Xpos2   ; get X2 value
  1231.     MOV     DX, [BP].DL_Ypos2   ; get Y2 value
  1232.  
  1233.     MOV        BP, SCREEN_WIDTH    ; Use BP for Line width to
  1234.                                 ; to avoid extra memory access
  1235.  
  1236.     SUB     DX, BX               ; figure Delta_Y
  1237.     JNC     @DL_DeltaYOK2          ; jump if Y2 >= Y1
  1238.  
  1239.     ADD     BX, DX               ; put Y2 into Y1
  1240.     NEG     DX                  ; abs(Delta_Y)
  1241.     XCHG    AX, CX               ; and exchange X1 and X2
  1242.  
  1243. @DL_DeltaYOK2:
  1244.     MOV     BX, 08000H           ; seed for fraction accumulator
  1245.  
  1246.     SUB     CX, AX               ; figure Delta_X
  1247.     JC        @DL_DrawLeft        ; if negative, go left
  1248.  
  1249.     JMP     @DL_DrawRight          ; Draw Line that slopes right
  1250.  
  1251. @DL_DrawLeft:
  1252.  
  1253.     NEG     CX                  ; abs(Delta_X)
  1254.  
  1255.     CMP     CX, DX               ; is Delta_X < Delta_Y?
  1256.     JB      @DL_SteepLeft          ; yes, so go do steep line
  1257.                                 ; (Delta_Y iterations)
  1258.  
  1259.     ; Draw a Shallow line to the left in Mode X
  1260.  
  1261. @DL_ShallowLeft:
  1262.     CLR     AX                       ; zero low word of Delta_Y * 10000h
  1263.     SUB        AX, DX                ; DX:AX <- DX * 0FFFFh
  1264.     SBB        DX, 0                ; include carry
  1265.     DIV     CX                  ; divide by Delta_X
  1266.  
  1267.     MOV        SI, BX                ; SI = Accumulator
  1268.     MOV        BX, AX                ; BX = Add fraction
  1269.     POP        AX                    ; Get Color, Bit mask
  1270.     MOV        DX, SC_Data            ; Sequence controller data register
  1271.     INC        CX                    ; Inc Delta_X so we can unroll loop
  1272.  
  1273.     ; Loop (x2) to Draw Pixels, Move Left, and Maybe Down... 
  1274.  
  1275. @DL_SLLLoop:
  1276.     MOV     ES:[DI], AH         ; set first pixel, plane data set up
  1277.     LOOPjz    CX, @DL_SLLExit        ; Delta_X--, Exit if done
  1278.  
  1279.     ADD     SI, BX               ; add numerator to accumulator
  1280.     JNC        @DL_SLLL2nc            ; move down on carry
  1281.  
  1282.     ADD        DI, BP                ; Move Down one line...
  1283.  
  1284. @DL_SLLL2nc:                
  1285.     DEC        DI                    ; Left one addr
  1286.     ROR        AL, 1                ; Move Left one plane, back on 0 1 2
  1287.     CMP        AL, 87h                ; wrap?, if AL <88 then Carry set
  1288.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry
  1289.     OUT        DX, AL                ; Set up New Bit Plane mask
  1290.  
  1291.     MOV     ES:[DI], AH         ; set pixel
  1292.     LOOPjz    CX, @DL_SLLExit        ; Delta_X--, Exit if done
  1293.  
  1294.     ADD     SI, BX               ; add numerator to accumulator, 
  1295.     JNC        @DL_SLLL3nc            ; move down on carry
  1296.  
  1297.     ADD        DI, BP                ; Move Down one line...
  1298.  
  1299. @DL_SLLL3nc:                    ; Now move left a pixel...
  1300.     DEC        DI                    ; Left one addr
  1301.     ROR        AL, 1                ; Move Left one plane, back on 0 1 2
  1302.     CMP        AL, 87h                ; Wrap?, if AL <88 then Carry set
  1303.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry
  1304.     OUT        DX, AL                ; Set up New Bit Plane mask
  1305.     JMP        s @DL_SLLLoop        ; loop until done
  1306.  
  1307. @DL_SLLExit:
  1308.     JMP        @DL_EXIT2            ; and exit
  1309.  
  1310.     ; Draw a steep line to the left in Mode X
  1311.  
  1312. @DL_SteepLeft:
  1313.     CLR     AX                       ; zero low word of Delta_Y * 10000h
  1314.     XCHG    DX, CX               ; Delta_Y switched with Delta_X
  1315.     DIV     CX                  ; divide by Delta_Y
  1316.  
  1317.     MOV        SI, BX                ; SI = Accumulator
  1318.     MOV        BX, AX                ; BX = Add Fraction
  1319.     POP        AX                    ; Get Color, Bit mask
  1320.     MOV        DX, SC_Data            ; Sequence controller data register
  1321.     INC        CX                    ; Inc Delta_Y so we can unroll loop
  1322.  
  1323.     ; Loop (x2) to Draw Pixels, Move Down, and Maybe left
  1324.  
  1325. @DL_STLLoop:
  1326.  
  1327.     MOV     ES:[DI], AH         ; set first pixel
  1328.     LOOPjz    CX, @DL_STLExit        ; Delta_Y--, Exit if done
  1329.  
  1330.     ADD     SI, BX               ; add numerator to accumulator
  1331.     JNC        @DL_STLnc2            ; No carry, just move down!
  1332.  
  1333.     DEC        DI                    ; Move Left one addr
  1334.     ROR        AL, 1                ; Move Left one plane, back on 0 1 2
  1335.     CMP        AL, 87h                ; Wrap?, if AL <88 then Carry set
  1336.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry
  1337.     OUT        DX, AL                ; Set up New Bit Plane mask
  1338.  
  1339. @DL_STLnc2:
  1340.     ADD     DI, BP                ; advance to next line.  
  1341.  
  1342.     MOV     ES:[DI], AH         ; set pixel
  1343.     LOOPjz    CX, @DL_STLExit        ; Delta_Y--, Exit if done
  1344.  
  1345.     ADD     SI, BX               ; add numerator to accumulator
  1346.     JNC        @DL_STLnc3            ; No carry, just move down!
  1347.  
  1348.     DEC        DI                    ; Move Left one addr
  1349.     ROR        AL, 1                ; Move Left one plane, back on 0 1 2
  1350.     CMP        AL, 87h                ; Wrap?, if AL <88 then Carry set
  1351.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry
  1352.     OUT        DX, AL                ; Set up New Bit Plane mask
  1353.  
  1354. @DL_STLnc3:
  1355.     ADD     DI, BP                ; advance to next line.  
  1356.     JMP        s @DL_STLLoop        ; Loop until done
  1357.  
  1358. @DL_STLExit:
  1359.     JMP        @DL_EXIT2            ; and exit
  1360.  
  1361.     ; Draw a line that goes to the Right...
  1362.  
  1363. @DL_DrawRight:
  1364.     CMP     CX, DX               ; is Delta_X < Delta_Y?
  1365.     JB      @DL_SteepRight         ; yes, so go do steep line 
  1366.                                 ; (Delta_Y iterations)
  1367.  
  1368.     ; Draw a Shallow line to the Right in Mode X
  1369.  
  1370. @DL_ShallowRight:
  1371.     CLR     AX                       ; zero low word of Delta_Y * 10000h
  1372.     SUB        AX, DX                ; DX:AX <- DX * 0FFFFh
  1373.     SBB     DX, 0                ; include carry
  1374.     DIV     CX                  ; divide by Delta_X
  1375.  
  1376.     MOV        SI, BX                ; SI = Accumulator
  1377.     MOV        BX, AX                ; BX = Add Fraction
  1378.     POP        AX                    ; Get Color, Bit mask
  1379.     MOV        DX, SC_Data            ; Sequence controller data register
  1380.     INC        CX                    ; Inc Delta_X so we can unroll loop
  1381.  
  1382.     ; Loop (x2) to Draw Pixels, Move Right, and Maybe Down... 
  1383.  
  1384. @DL_SLRLoop:
  1385.     MOV     ES:[DI], AH         ; set first pixel, mask is set up
  1386.     LOOPjz    CX, @DL_SLRExit        ; Delta_X--, Exit if done..
  1387.  
  1388.     ADD     SI, BX               ; add numerator to accumulator
  1389.     JNC        @DL_SLR2nc            ; don't move down if carry not set
  1390.  
  1391.     ADD        DI, BP                ; Move Down one line...
  1392.  
  1393. @DL_SLR2nc:                        ; Now move right a pixel...
  1394.     ROL        AL, 1                ; Move Right one addr if Plane = 0
  1395.     CMP        AL, 12h                ; Wrap? if AL >12 then Carry not set
  1396.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry
  1397.     OUT        DX, AL                ; Set up New Bit Plane mask
  1398.  
  1399.     MOV     ES:[DI], AH            ; set pixel
  1400.     LOOPjz    CX, @DL_SLRExit        ; Delta_X--, Exit if done..
  1401.  
  1402.     ADD     SI, BX               ; add numerator to accumulator
  1403.     JNC        @DL_SLR3nc            ; don't move down if carry not set
  1404.  
  1405.     ADD        DI, BP                ; Move Down one line...
  1406.  
  1407. @DL_SLR3nc:                        
  1408.     ROL        AL, 1                ; Move Right one addr if Plane = 0
  1409.     CMP        AL, 12h                ; Wrap? if AL >12 then Carry not set
  1410.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry
  1411.     OUT        DX, AL                ; Set up New Bit Plane mask
  1412.     JMP     s @DL_SLRLoop        ; loop till done
  1413.  
  1414. @DL_SLRExit:
  1415.     JMP        @DL_EXIT2            ; and exit
  1416.  
  1417.     ; Draw a Steep line to the Right in Mode X
  1418.  
  1419. @DL_SteepRight:
  1420.     CLR     AX                       ; zero low word of Delta_Y * 10000h
  1421.     XCHG    DX, CX               ; Delta_Y switched with Delta_X
  1422.     DIV     CX                  ; divide by Delta_Y
  1423.  
  1424.     MOV        SI, BX                ; SI = Accumulator
  1425.     MOV        BX, AX                ; BX = Add Fraction
  1426.     POP        AX                    ; Get Color, Bit mask
  1427.     MOV        DX, SC_Data            ; Sequence controller data register
  1428.     INC        CX                    ; Inc Delta_Y so we can unroll loop
  1429.  
  1430.     ; Loop (x2) to Draw Pixels, Move Down, and Maybe Right
  1431.  
  1432. @STRLoop:
  1433.     MOV     ES:[DI], AH         ; set first pixel, mask is set up
  1434.     LOOPjz    CX, @DL_EXIT2        ; Delta_Y--, Exit if Done
  1435.  
  1436.     ADD     SI, BX               ; add numerator to accumulator
  1437.     JNC        @STRnc2                ; if no carry then just go down...
  1438.  
  1439.     ROL        AL, 1                ; Move Right one addr if Plane = 0
  1440.     CMP        AL, 12h                ; Wrap? if AL >12 then Carry not set
  1441.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry 
  1442.     OUT        DX, AL                ; Set up New Bit Plane mask
  1443.  
  1444. @STRnc2:
  1445.     ADD     DI, BP                ; advance to next line.
  1446.  
  1447.     MOV     ES:[DI], AH         ; set pixel
  1448.     LOOPjz    CX, @DL_EXIT2        ; Delta_Y--, Exit if Done
  1449.  
  1450.     ADD     SI, BX               ; add numerator to accumulator
  1451.     JNC        @STRnc3                ; if no carry then just go down...
  1452.  
  1453.     ROL        AL, 1                ; Move Right one addr if Plane = 0
  1454.     CMP        AL, 12h                ; Wrap? if AL >12 then Carry not set
  1455.     ADC        DI, 0                ; Adjust Address: DI = DI + Carry 
  1456.     OUT        DX, AL                ; Set up New Bit Plane mask
  1457.  
  1458. @STRnc3:
  1459.     ADD     DI, BP                ; advance to next line.
  1460.     JMP        s @STRLoop            ; loop till done
  1461.  
  1462. @DL_EXIT2:
  1463.     POPx    DI, SI, BP            ; Restore Saved Registers
  1464.     RET     10                  ; Exit and Clean up Stack
  1465.  
  1466. DRAW_LINE        ENDP
  1467.  
  1468.  
  1469.     ; ===== DAC COLOR REGISTER ROUTINES =====
  1470.  
  1471. ;=================================================
  1472. ;SET_DAC_REGISTER (Register%, Red%, Green%, Blue%)
  1473. ;=================================================
  1474. ;
  1475. ; Sets a single (RGB) Vga Palette Register
  1476. ;
  1477. ; ENTRY: Register = The DAC # to modify (0-255)
  1478. ;        Red      = The new Red Intensity (0-63)
  1479. ;        Green    = The new Green Intensity (0-63)
  1480. ;        Blue     = The new Blue Intensity (0-63)
  1481. ;
  1482. ; EXIT:  No meaningful values returned
  1483. ;
  1484.  
  1485. SDR_STACK    STRUC
  1486.                       DW    ?    ; BP
  1487.                     DD    ?    ; Caller
  1488.     SDR_Blue        DB    ?,?    ; Blue Data Value
  1489.     SDR_Green        DB    ?,?    ; Green Data Value
  1490.     SDR_Red            DB    ?,?    ; Red Data Value
  1491.     SDR_Register    DB    ?,?    ; Palette Register #
  1492. SDR_STACK    ENDS
  1493.  
  1494.     PUBLIC    SET_DAC_REGISTER
  1495.  
  1496. SET_DAC_REGISTER    PROC    FAR
  1497.  
  1498.     PUSH    BP                    ; Save BP
  1499.     MOV     BP, SP                ; Set up Stack Frame
  1500.  
  1501.     ; Select which DAC Register to modify
  1502.  
  1503.     OUT_8    DAC_WRITE_ADDR, [BP].SDR_Register
  1504.  
  1505.     MOV        DX, PEL_DATA_REG    ; Dac Data Register
  1506.     OUT_8    DX, [BP].SDR_Red    ; Set Red Intensity
  1507.     OUT_8    DX, [BP].SDR_Green    ; Set Green Intensity
  1508.     OUT_8    DX, [BP].SDR_Blue    ; Set Blue Intensity
  1509.  
  1510.     POP        BP                    ; Restore Registers
  1511.     RET        8                    ; Exit & Clean Up Stack
  1512.  
  1513. SET_DAC_REGISTER    ENDP
  1514.  
  1515. ;====================================================
  1516. ;GET_DAC_REGISTER (Register%, &Red%, &Green%, &Blue%)
  1517. ;====================================================
  1518. ;
  1519. ; Reads the RGB Values of a single Vga Palette Register
  1520. ;
  1521. ; ENTRY: Register = The DAC # to read (0-255)
  1522. ;        Red      = Offset to Red Variable in DS
  1523. ;        Green    = Offset to Green Variable in DS
  1524. ;        Blue     = Offset to Blue Variable in DS
  1525. ;
  1526. ; EXIT:  The values of the integer variables Red, 
  1527. ;         Green, and Blue are set to the values
  1528. ;        taken from the specified DAC register.
  1529. ;
  1530.  
  1531. GDR_STACK    STRUC
  1532.                     DW    ?    ; BP
  1533.                     DD    ?    ; Caller
  1534.     GDR_Blue        DW    ?    ; Addr of Blue Data Value in DS
  1535.     GDR_Green        DW    ?    ; Addr of Green Data Value in DS
  1536.     GDR_Red            DW    ?    ; Addr of Red Data Value in DS
  1537.     GDR_Register    DB    ?,?    ; Palette Register #
  1538. GDR_STACK    ENDS
  1539.  
  1540.     PUBLIC    GET_DAC_REGISTER
  1541.  
  1542. GET_DAC_REGISTER    PROC    FAR
  1543.  
  1544.     PUSH    BP                    ; Save BP
  1545.     MOV     BP, SP                ; Set up Stack Frame
  1546.  
  1547.     ; Select which DAC Register to read in
  1548.  
  1549.     OUT_8    DAC_READ_ADDR, [BP].GDR_Register
  1550.  
  1551.     MOV        DX, PEL_DATA_REG    ; Dac Data Register
  1552.     CLR        AX                    ; Clear AX
  1553.  
  1554.     IN        AL, DX                ; Read Red Value
  1555.     MOV        BX, [BP].GDR_Red    ; Get Address of Red%
  1556.     MOV        [BX], AX            ; *Red% = AX
  1557.  
  1558.     IN        AL, DX                ; Read Green Value
  1559.     MOV        BX, [BP].GDR_Green    ; Get Address of Green%
  1560.     MOV        [BX], AX            ; *Green% = AX
  1561.  
  1562.     IN        AL, DX                ; Read Blue Value
  1563.     MOV        BX, [BP].GDR_Blue    ; Get Address of Blue%
  1564.     MOV        [BX], AX            ; *Blue% = AX
  1565.  
  1566.     POP        BP                    ; Restore Registers
  1567.     RET        8                    ; Exit & Clean Up Stack
  1568.  
  1569. GET_DAC_REGISTER    ENDP
  1570.  
  1571.  
  1572.     ; ===== PAGE FLIPPING AND SCROLLING ROUTINES =====
  1573.  
  1574. ;=========================
  1575. ;SET_ACTIVE_PAGE (PageNo%)
  1576. ;=========================
  1577. ;
  1578. ; Sets the active display Page to be used for future drawing
  1579. ;
  1580. ; ENTRY: PageNo = Display Page to make active
  1581. ;        (values: 0 to Number of Pages - 1)
  1582. ;
  1583. ; EXIT:  No meaningful values returned
  1584. ;
  1585.  
  1586. SAP_STACK    STRUC
  1587.                 DW    ?    ; BP
  1588.                 DD    ?    ; Caller
  1589.     SAP_Page    DW    ?    ; Page # for Drawing
  1590. SAP_STACK    ENDS
  1591.  
  1592.     PUBLIC    SET_ACTIVE_PAGE
  1593.  
  1594. SET_ACTIVE_PAGE    PROC    FAR
  1595.  
  1596.     PUSH    BP                    ; Preserve Registers
  1597.     MOV        BP, SP                ; Set up Stack Frame
  1598.  
  1599.     MOV        BX, [BP].SAP_Page    ; Get Desired Page #
  1600.     CMP        BX, LAST_PAGE        ; Is Page # Valid?
  1601.     JAE        @SAP_Exit            ; IF Not, Do Nothing
  1602.  
  1603.     MOV        ACTIVE_PAGE, BX        ; Set Active Page #
  1604.  
  1605.     SHL        BX, 1                ; Scale Page # to Word
  1606.     MOV        AX, PAGE_ADDR[BX]    ; Get offset to Page
  1607.  
  1608.     MOV        CURRENT_PAGE, AX    ; And set for future LES's
  1609.  
  1610. @SAP_Exit:
  1611.     POP        BP                    ; Restore Registers
  1612.     RET     2                    ; Exit and Clean up Stack
  1613.  
  1614. SET_ACTIVE_PAGE    ENDP
  1615.  
  1616.  
  1617. ;================
  1618. ;GET_ACTIVE_PAGE%
  1619. ;================
  1620. ;
  1621. ; Returns the Video Page # currently used for Drawing
  1622. ;
  1623. ; ENTRY: No Parameters are passed
  1624. ;
  1625. ; EXIT:  AX = Current Video Page used for Drawing
  1626. ;
  1627.  
  1628.     PUBLIC    GET_ACTIVE_PAGE
  1629.  
  1630. GET_ACTIVE_PAGE    PROC    FAR
  1631.  
  1632.     MOV        AX, ACTIVE_PAGE        ; Get Active Page #
  1633.     RET                         ; Exit and Clean up Stack
  1634.  
  1635. GET_ACTIVE_PAGE    ENDP
  1636.  
  1637.  
  1638. ;===============================
  1639. ;SET_DISPLAY_PAGE (DisplayPage%)
  1640. ;===============================
  1641. ;
  1642. ; Sets the currently visible display page.
  1643. ; When called this routine syncronizes the display 
  1644. ; to the vertical blank.
  1645. ;
  1646. ; ENTRY: PageNo = Display Page to show on the screen
  1647. ;        (values: 0 to Number of Pages - 1)
  1648. ;
  1649. ; EXIT:  No meaningful values returned
  1650. ;
  1651.  
  1652. SDP_STACK    STRUC
  1653.                 DW    ?        ; BP
  1654.                 DD    ?        ; Caller
  1655.     SDP_Page    DW    ?        ; Page # to Display...
  1656. SDP_STACK    ENDS
  1657.  
  1658.     PUBLIC    SET_DISPLAY_PAGE
  1659.  
  1660. SET_DISPLAY_PAGE    PROC    FAR
  1661.  
  1662.     PUSH    BP                    ; Preserve Registers
  1663.     MOV        BP, SP                ; Set up Stack Frame
  1664.  
  1665.     MOV        BX, [BP].SDP_Page    ; Get Desired Page #
  1666.     CMP        BX, LAST_PAGE        ; Is Page # Valid?
  1667.     JAE        @SDP_Exit            ; IF Not, Do Nothing
  1668.  
  1669.     MOV        DISPLAY_PAGE, BX    ; Set Display Page #
  1670.  
  1671.     SHL        BX, 1                ; Scale Page # to Word
  1672.     MOV        CX, PAGE_ADDR[BX]    ; Get offset in memory to Page
  1673.     ADD        CX, CURRENT_MOFFSET    ; Adjust for any scrolling
  1674.  
  1675.     ; Wait if we are currently in a Vertical Retrace
  1676.  
  1677.     MOV        DX, INPUT_1            ; Input Status #1 Register
  1678.  
  1679. @DP_WAIT0:
  1680.     IN        AL, DX                ; Get VGA status
  1681.     AND        AL, VERT_RETRACE    ; In Display mode yet?
  1682.     JNZ        @DP_WAIT0            ; If Not, wait for it
  1683.  
  1684.     ; Set the Start Display Address to the new page
  1685.  
  1686.     MOV        DX, CRTC_Index        ; We Change the VGA Sequencer
  1687.  
  1688.     MOV        AL, START_DISP_LO    ; Display Start Low Register
  1689.     MOV        AH, CL                ; Low 8 Bits of Start Addr
  1690.     OUT        DX, AX                ; Set Display Addr Low
  1691.  
  1692.     MOV        AL, START_DISP_HI    ; Display Start High Register
  1693.     MOV        AH, CH                ; High 8 Bits of Start Addr
  1694.     OUT        DX, AX                ; Set Display Addr High
  1695.  
  1696.     ; Wait for a Vertical Retrace to smooth out things
  1697.  
  1698.     MOV        DX, INPUT_1            ; Input Status #1 Register
  1699.  
  1700. @DP_WAIT1:
  1701.     IN        AL, DX                ; Get VGA status
  1702.     AND        AL, VERT_RETRACE    ; Vertical Retrace Start?
  1703.     JZ        @DP_WAIT1            ; If Not, wait for it
  1704.  
  1705.     ; Now Set Display Starting Address
  1706.  
  1707.  
  1708. @SDP_Exit:
  1709.     POP        BP                    ; Restore Registers
  1710.     RET     2                    ; Exit and Clean up Stack
  1711.  
  1712. SET_DISPLAY_PAGE    ENDP
  1713.  
  1714.  
  1715. ;=================
  1716. ;GET_DISPLAY_PAGE%
  1717. ;=================
  1718. ;
  1719. ; Returns the Video Page # currently displayed
  1720. ;
  1721. ; ENTRY: No Parameters are passed
  1722. ;
  1723. ; EXIT:  AX = Current Video Page being displayed
  1724. ;
  1725.  
  1726.     PUBLIC    GET_DISPLAY_PAGE
  1727.  
  1728. GET_DISPLAY_PAGE    PROC    FAR
  1729.  
  1730.     MOV        AX, DISPLAY_PAGE    ; Get Display Page #
  1731.     RET                         ; Exit & Clean Up Stack
  1732.  
  1733. GET_DISPLAY_PAGE    ENDP
  1734.  
  1735.  
  1736. ;=======================================
  1737. ;SET_WINDOW (DisplayPage%, Xpos%, Ypos%)
  1738. ;=======================================
  1739. ;
  1740. ; Since a Logical Screen can be larger than the Physical
  1741. ; Screen, Scrolling is possible.  This routine sets the
  1742. ; Upper Left Corner of the Screen to the specified Pixel.
  1743. ; Also Sets the Display page to simplify combined page
  1744. ; flipping and scrolling.  When called this routine
  1745. ; syncronizes the display to the vertical blank.
  1746. ;
  1747. ; ENTRY: DisplayPage = Display Page to show on the screen
  1748. ;        Xpos        = # of pixels to shift screen right
  1749. ;        Ypos        = # of lines to shift screen down
  1750. ;
  1751. ; EXIT:  No meaningful values returned
  1752. ;
  1753.  
  1754. SW_STACK    STRUC
  1755.                 DW    ?    ; BP
  1756.                 DD    ?    ; Caller
  1757.     SW_Ypos        DW    ?    ; Y pos of UL Screen Corner
  1758.     SW_Xpos        DW    ?   ; X pos of UL Screen Corner
  1759.     SW_Page        DW    ?    ; (new) Display Page
  1760. SW_STACK    ENDS
  1761.  
  1762.         PUBLIC SET_WINDOW
  1763.  
  1764. SET_WINDOW    PROC    FAR
  1765.  
  1766.     PUSH    BP                    ; Preserve Registers
  1767.     MOV        BP, SP                ; Set up Stack Frame
  1768.  
  1769.     ; Check if our Scroll Offsets are Valid
  1770.  
  1771.     MOV        BX, [BP].SW_Page    ; Get Desired Page #
  1772.     CMP        BX, LAST_PAGE        ; Is Page # Valid?
  1773.     JAE        @SW_Exit            ; IF Not, Do Nothing
  1774.  
  1775.     MOV        AX, [BP].SW_Ypos    ; Get Desired Y Offset
  1776.     CMP        AX, MAX_YOFFSET        ; Is it Within Limits?
  1777.     JA        @SW_Exit            ; if not, exit
  1778.  
  1779.     MOV        CX, [BP].SW_Xpos    ; Get Desired X Offset
  1780.     CMP        CX, MAX_XOFFSET        ; Is it Within Limits?
  1781.     JA        @SW_Exit            ; if not, exit
  1782.  
  1783.     ; Compute proper Display start address to use
  1784.  
  1785.     MUL        SCREEN_WIDTH        ; AX = YOffset * Line Width
  1786.     SHR        CX, 2                ; CX / 4 = Bytes into Line
  1787.     ADD        AX, CX                ; AX = Offset of Upper Left Pixel
  1788.  
  1789.     MOV        CURRENT_MOFFSET, AX    ; Save Offset Info
  1790.  
  1791.     MOV        DISPLAY_PAGE, BX    ; Set Current Page #
  1792.     SHL        BX, 1                ; Scale Page # to Word
  1793.     ADD        AX, PAGE_ADDR[BX]    ; Get offset in VGA to Page
  1794.     MOV        BX, AX                ; BX = Desired Display Start
  1795.  
  1796.     MOV        DX, INPUT_1            ; Input Status #1 Register
  1797.  
  1798.     ; Wait if we are currently in a Vertical Retrace
  1799.  
  1800. @SW_WAIT0:
  1801.     IN        AL, DX                ; Get VGA status
  1802.     AND        AL, VERT_RETRACE    ; In Display mode yet?
  1803.     JNZ        @SW_WAIT0            ; If Not, wait for it
  1804.  
  1805.     ; Set the Start Display Address to the new window
  1806.  
  1807.     MOV        DX, CRTC_Index        ; We Change the VGA Sequencer
  1808.     MOV        AL, START_DISP_LO    ; Display Start Low Register
  1809.     MOV        AH, BL                ; Low 8 Bits of Start Addr
  1810.     OUT        DX, AX                ; Set Display Addr Low
  1811.  
  1812.     MOV        AL, START_DISP_HI    ; Display Start High Register
  1813.     MOV        AH, BH                ; High 8 Bits of Start Addr
  1814.     OUT        DX, AX                ; Set Display Addr High
  1815.  
  1816.     ; Wait for a Vertical Retrace to smooth out things
  1817.  
  1818.     MOV        DX, INPUT_1            ; Input Status #1 Register
  1819.  
  1820. @SW_WAIT1:
  1821.     IN        AL, DX                ; Get VGA status
  1822.     AND        AL, VERT_RETRACE    ; Vertical Retrace Start?
  1823.     JZ        @SW_WAIT1            ; If Not, wait for it
  1824.  
  1825.        ; Now Set the Horizontal Pixel Pan values
  1826.  
  1827.     OUT_8    ATTRIB_Ctrl, PIXEL_PAN_REG    ; Select Pixel Pan Register    
  1828.      
  1829.     MOV        AX, [BP].SW_Xpos    ; Get Desired X Offset
  1830.     AND        AL, 03                ; Get # of Pixels to Pan (0-3)
  1831.     SHL        AL, 1                ; Shift for 256 Color Mode
  1832.     OUT        DX, AL                ; Fine tune the display!
  1833.  
  1834. @SW_Exit:
  1835.     POP        BP                    ; Restore Saved Registers
  1836.     RET     6                   ; Exit and Clean up Stack
  1837.  
  1838. SET_WINDOW        ENDP
  1839.  
  1840.  
  1841. ;=============
  1842. ;GET_X_OFFSET%
  1843. ;=============
  1844. ;
  1845. ; Returns the X coordinate of the Pixel currently display
  1846. ; in the upper left corner of the display
  1847. ;
  1848. ; ENTRY: No Parameters are passed
  1849. ;
  1850. ; EXIT:  AX = Current Horizontal Scroll Offset
  1851. ;
  1852.  
  1853.     PUBLIC    GET_X_OFFSET
  1854.  
  1855. GET_X_OFFSET    PROC    FAR
  1856.  
  1857.     MOV        AX, CURRENT_XOFFSET    ; Get current horz offset
  1858.     RET                         ; Exit & Clean Up Stack
  1859.  
  1860. GET_X_OFFSET    ENDP
  1861.  
  1862.  
  1863. ;=============
  1864. ;GET_Y_OFFSET%
  1865. ;=============
  1866. ;
  1867. ; Returns the Y coordinate of the Pixel currently display
  1868. ; in the upper left corner of the display
  1869. ;
  1870. ; ENTRY: No Parameters are passed
  1871. ;
  1872. ; EXIT:  AX = Current Vertical Scroll Offset
  1873. ;
  1874.  
  1875.     PUBLIC    GET_Y_OFFSET
  1876.  
  1877. GET_Y_OFFSET    PROC    FAR
  1878.  
  1879.     MOV        AX, CURRENT_YOFFSET    ; Get current vertical offset
  1880.     RET                         ; Exit & Clean Up Stack
  1881.  
  1882. GET_Y_OFFSET    ENDP
  1883.  
  1884.  
  1885. ;============
  1886. ;SYNC_DISPLAY
  1887. ;============
  1888. ;
  1889. ; Pauses the computer until the next Vertical Retrace starts
  1890. ;
  1891. ; ENTRY: No Parameters are passed
  1892. ;
  1893. ; EXIT:  No meaningful values returned
  1894. ;
  1895.  
  1896.     PUBLIC    SYNC_DISPLAY
  1897.  
  1898. SYNC_DISPLAY    PROC    FAR
  1899.  
  1900.     MOV        DX, INPUT_1            ; Input Status #1 Register
  1901.  
  1902.     ; Wait for any current retrace to end
  1903.  
  1904. @SD_WAIT0:
  1905.     IN        AL, DX                ; Get VGA status
  1906.     AND        AL, VERT_RETRACE    ; In Display mode yet?
  1907.     JNZ        @SD_WAIT0            ; If Not, wait for it
  1908.  
  1909.     ; Wait for the start of the next vertical retrace
  1910.  
  1911. @SD_WAIT1:
  1912.     IN        AL, DX                ; Get VGA status
  1913.     AND        AL, VERT_RETRACE    ; Vertical Retrace Start?
  1914.     JZ        @SD_WAIT1            ; If Not, wait for it
  1915.  
  1916.     RET                         ; Exit & Clean Up Stack
  1917.  
  1918. SYNC_DISPLAY    ENDP
  1919.     
  1920.  
  1921.     ; ===== TEXT DISPLAY ROUTINES =====
  1922.  
  1923. ;==================================================
  1924. ;GPRINTC (CharNum%, Xpos%, Ypos%, ColorF%, ColorB%)
  1925. ;==================================================
  1926. ;
  1927. ; Draws an ASCII Text Character using the currently selected
  1928. ; 8x8 font on the active display page.  It would be a simple
  1929. ; exercise to make this routine process variable height fonts.
  1930. ;
  1931. ; ENTRY: CharNum = ASCII character # to draw
  1932. ;         Xpos    = X position to draw Character at
  1933. ;        Ypos    = Y position of to draw Character at
  1934. ;        ColorF  = Color to draw text character in
  1935. ;        ColorB  = Color to set background to
  1936. ;
  1937. ; EXIT:  No meaningful values returned
  1938. ;
  1939.  
  1940. GPC_STACK    STRUC
  1941.     GPC_Width    DW    ?    ; Screen Width-1
  1942.     GPC_Lines    DB    ?,?    ; Scan lines to Decode
  1943.     GPC_T_SETS    DW    ?    ; Saved Charset Segment
  1944.     GPC_T_SETO    DW    ?    ; Saved Charset Offset
  1945.                     DW    ?x4    ; DI, SI, DS, BP
  1946.                 DD    ?      ; Caller
  1947.     GPC_ColorB    DB    ?,?    ; Background Color
  1948.     GPC_ColorF    DB    ?,?    ; Text Color
  1949.     GPC_Ypos    DW    ?    ; Y Position to Print at
  1950.     GPC_Xpos    DW    ?    ; X position to Print at
  1951.     GPC_Char    DB    ?,?    ; Character to Print
  1952. GPC_STACK    ENDS
  1953.  
  1954.         PUBLIC GPRINTC
  1955.  
  1956. GPRINTC        PROC    FAR
  1957.  
  1958.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  1959.     SUB        SP, 8                ; Allocate WorkSpace on Stack
  1960.     MOV        BP, SP                ; Set up Stack Frame
  1961.  
  1962.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  1963.  
  1964.     MOV        AX, SCREEN_WIDTH    ; Get Logical Line Width
  1965.     MOV        BX, AX                ; BX = Screen Width
  1966.     DEC        BX                    ;    = Screen Width-1
  1967.     MOV        [BP].GPC_Width, BX    ; Save for later use
  1968.  
  1969.     MUL        [BP].GPC_Ypos        ; Start of Line = Ypos * Width
  1970.     ADD        DI, AX                ; DI -> Start of Line Ypos
  1971.  
  1972.     MOV     AX, [BP].GPC_Xpos    ; Get Xpos of Character
  1973.     MOV        CX, AX                ; Save Copy of Xpos
  1974.     SHR        AX, 2                ; Bytes into Line = Xpos/4
  1975.     ADD        DI, AX                ; DI -> (Xpos, Ypos)
  1976.  
  1977.     ;Get Source ADDR of Character Bit Map  & Save
  1978.  
  1979.     MOV     AL, [BP].GPC_Char    ; Get Character #
  1980.     TEST     AL, 080h            ; Is Hi Bit Set?
  1981.     JZ        @GPC_LowChar        ; Nope, use low char set ptr
  1982.  
  1983.     AND        AL, 07Fh            ; Mask Out Hi Bit
  1984.     MOV        BX, CHARSET_HI        ; BX = Char Set Ptr:Offset
  1985.     MOV        DX, CHARSET_HI+2    ; DX = Char Set Ptr:Segment
  1986.     JMP        s @GPC_Set_Char        ; Go Setup Character Ptr
  1987.  
  1988. @GPC_LowChar:
  1989.  
  1990.     MOV        BX, CHARSET_LOW        ; BX = Char Set Ptr:Offset
  1991.     MOV        DX, CHARSET_LOW+2    ; DX = Char Set Ptr:Segment
  1992.  
  1993. @GPC_Set_Char:
  1994.     MOV        [BP].GPC_T_SETS, DX    ; Save Segment on Stack
  1995.  
  1996.     MOV     AH, 0                   ; Valid #'s are 0..127
  1997.     SHL     AX, 3               ; * 8 Bytes Per Bitmap
  1998.     ADD        BX, AX                ; BX = Offset of Selected char
  1999.     MOV        [BP].GPC_T_SETO, BX    ; Save Offset on Stack
  2000.  
  2001.     AND        CX, PLANE_BITS        ; Get Plane #
  2002.     MOV        CH, ALL_PLANES        ; Get Initial Plane mask
  2003.     SHL        CH, CL                ; And shift into position
  2004.     AND        CH, ALL_PLANES        ; And mask to lower nibble
  2005.  
  2006.     MOV        AL, 04                ; 4-Plane # = # of initial
  2007.     SUB        AL, CL                ; shifts to align bit mask 
  2008.     MOV        CL, AL                ; Shift Count for SHL
  2009.     
  2010.     ;Get segment of character map
  2011.  
  2012.     OUT_8    SC_Index, MAP_MASK    ; Setup Plane selections
  2013.     INC        DX                    ; DX -> SC_Data
  2014.  
  2015.     MOV        AL, 08                ; 8 Lines to Process
  2016.     MOV        [BP].GPC_Lines, AL    ; Save on Stack
  2017.  
  2018.     MOV        DS, [BP].GPC_T_SETS    ; Point to character set
  2019.  
  2020. @GPC_DECODE_CHAR_BYTE:
  2021.  
  2022.     MOV     SI, [BP].GPC_T_SETO ; Get DS:SI = String
  2023.  
  2024.     MOV        BH, [SI]            ; Get Bit Map
  2025.     INC        SI                    ; Point to Next Line
  2026.     MOV     [BP].GPC_T_SETO, SI    ; And save new Pointer...
  2027.  
  2028.     CLR        AX                    ; Clear AX
  2029.  
  2030.     CLR        BL                        ; Clear BL
  2031.     ROL        BX, CL                    ; BL holds left edge bits
  2032.     MOV        SI, BX                    ; Use as Table Index
  2033.     AND        SI, CHAR_BITS            ; Get Low Bits
  2034.     MOV        AL, Char_Plane_Data[SI]    ; Get Mask in AL
  2035.     JZ        @GPC_NO_LEFT1BITS        ; Skip if No Pixels to set
  2036.  
  2037.     MOV        AH, [BP].GPC_ColorF    ; Get Foreground Color
  2038.     OUT        DX, AL                ; Set up Screen Mask
  2039.     MOV        ES:[DI], AH            ; Write Foreground color
  2040.  
  2041. @GPC_NO_LEFT1BITS:
  2042.     XOR        AL, CH                ; Invert mask for Background
  2043.     JZ        @GPC_NO_LEFT0BITS    ; Hey, no need for this
  2044.  
  2045.     MOV        AH, [BP].GPC_ColorB    ; Get background Color
  2046.     OUT        DX, AL                ; Set up Screen Mask
  2047.     MOV        ES:[DI], AH            ; Write Foreground color
  2048.  
  2049.     ;Now Do Middle/Last Band
  2050.  
  2051. @GPC_NO_LEFT0BITS:
  2052.     INC        DI                    ; Point to next Byte
  2053.     ROL        BX, 4                ; Shift 4 bits
  2054.     
  2055.     MOV        SI, BX                    ; Make Lookup Pointer
  2056.     AND        SI, CHAR_BITS            ; Get Low Bits
  2057.     MOV        AL, Char_Plane_Data[SI]    ; Get Mask in AL
  2058.     JZ        @GPC_NO_MIDDLE1BITS        ; Skip if no pixels to set
  2059.  
  2060.     MOV        AH, [BP].GPC_ColorF    ; Get Foreground Color
  2061.     OUT        DX, AL                ; Set up Screen Mask
  2062.     MOV        ES:[DI], AH            ; Write Foreground color
  2063.  
  2064. @GPC_NO_MIDDLE1BITS:
  2065.     XOR        AL, ALL_PLANES        ; Invert mask for Background
  2066.     JZ        @GPC_NO_MIDDLE0BITS    ; Hey, no need for this
  2067.  
  2068.     MOV        AH, [BP].GPC_ColorB    ; Get background Color
  2069.     OUT        DX, AL                ; Set up Screen Mask
  2070.     MOV        ES:[DI], AH            ; Write Foreground color
  2071.  
  2072. @GPC_NO_MIDDLE0BITS:
  2073.     XOR        CH, ALL_PLANES        ; Invert Clip Mask
  2074.     CMP        CL, 4                ; Aligned by 4?
  2075.     JZ        @GPC_NEXT_LINE        ; If so, Exit now..
  2076.  
  2077.     INC        DI                    ; Point to next Byte
  2078.     ROL        BX, 4                ; Shift 4 bits
  2079.  
  2080.     MOV        SI, BX                     ; Make Lookup Pointer
  2081.     AND        SI, CHAR_BITS            ; Get Low Bits
  2082.     MOV        AL, Char_Plane_Data[SI]    ; Get Mask in AL
  2083.     JZ        @GPC_NO_RIGHT1BITS        ; Skip if No Pixels to set
  2084.  
  2085.     MOV        AH, [BP].GPC_ColorF    ; Get Foreground Color
  2086.     OUT        DX, AL                ; Set up Screen Mask
  2087.     MOV        ES:[DI], AH            ; Write Foreground color
  2088.  
  2089. @GPC_NO_RIGHT1BITS:
  2090.  
  2091.     XOR        AL, CH                ; Invert mask for Background
  2092.     JZ        @GPC_NO_RIGHT0BITS    ; Hey, no need for this
  2093.  
  2094.     MOV        AH, [BP].GPC_ColorB    ; Get background Color
  2095.     OUT        DX, AL                ; Set up Screen Mask
  2096.     MOV        ES:[DI], AH            ; Write Foreground color
  2097.  
  2098. @GPC_NO_RIGHT0BITS:
  2099.     DEC        DI                    ; Adjust for Next Line Advance
  2100.  
  2101. @GPC_NEXT_LINE:
  2102.     ADD        DI, [BP].GPC_Width    ; Point to Next Line
  2103.     XOR        CH, CHAR_BITS        ; Flip the Clip mask back
  2104.  
  2105.     DEC        [BP].GPC_Lines        ; Count Down Lines
  2106.     JZ        @GPC_EXIT            ; Ok... Done!
  2107.  
  2108.     JMP        @GPC_DECODE_CHAR_BYTE    ; Again! Hey!
  2109.  
  2110. @GPC_EXIT:
  2111.     ADD        SP, 08                ; Deallocate stack workspace
  2112.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2113.     RET     10                     ; Exit and Clean up Stack
  2114.  
  2115. GPRINTC  ENDP
  2116.  
  2117.  
  2118. ;==========================================
  2119. ;TGPRINTC (CharNum%, Xpos%, Ypos%, ColorF%)
  2120. ;==========================================
  2121. ;
  2122. ; Transparently draws an ASCII Text Character using the
  2123. ; currently selected 8x8 font on the active display page.
  2124. ;
  2125. ; ENTRY: CharNum = ASCII character # to draw
  2126. ;         Xpos    = X position to draw Character at
  2127. ;        Ypos    = Y position of to draw Character at
  2128. ;        ColorF  = Color to draw text character in
  2129. ;
  2130. ; EXIT:  No meaningful values returned
  2131. ;
  2132.  
  2133. TGP_STACK    STRUC
  2134.     TGP_Width    DW    ?    ; Screen Width-1
  2135.     TGP_Lines    DB    ?,?    ; Scan lines to Decode
  2136.     TGP_T_SETS    DW    ?    ; Saved Charset Segment
  2137.     TGP_T_SETO    DW    ?    ; Saved Charset Offset
  2138.                     DW    ?x4    ; DI, SI, DS, BP
  2139.                 DD    ?    ; Caller
  2140.     TGP_ColorF    DB    ?,?    ; Text Color
  2141.     TGP_Ypos    DW    ?    ; Y Position to Print at
  2142.     TGP_Xpos    DW    ?    ; X position to Print at
  2143.     TGP_Char    DB    ?,?    ; Character to Print
  2144. TGP_STACK    ENDS
  2145.  
  2146.         PUBLIC TGPRINTC
  2147.  
  2148. TGPRINTC    PROC    FAR
  2149.  
  2150.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2151.     SUB        SP, 8                ; Allocate WorkSpace on Stack
  2152.     MOV        BP, SP                ; Set up Stack Frame
  2153.  
  2154.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  2155.  
  2156.     MOV        AX, SCREEN_WIDTH    ; Get Logical Line Width
  2157.     MOV        BX, AX                ; BX = Screen Width
  2158.     DEC        BX                    ;    = Screen Width-1
  2159.     MOV        [BP].TGP_Width, BX    ; Save for later use
  2160.  
  2161.     MUL        [BP].TGP_Ypos        ; Start of Line = Ypos * Width
  2162.     ADD        DI, AX                ; DI -> Start of Line Ypos
  2163.  
  2164.     MOV     AX, [BP].TGP_Xpos    ; Get Xpos of Character
  2165.     MOV        CX, AX                ; Save Copy of Xpos
  2166.     SHR        AX, 2                ; Bytes into Line = Xpos/4
  2167.     ADD        DI, AX                ; DI -> (Xpos, Ypos)
  2168.  
  2169.     ;Get Source ADDR of Character Bit Map  & Save
  2170.  
  2171.     MOV     AL, [BP].TGP_Char    ; Get Character #
  2172.     TEST     AL, 080h            ; Is Hi Bit Set?
  2173.     JZ        @TGP_LowChar        ; Nope, use low char set ptr
  2174.  
  2175.     AND        AL, 07Fh            ; Mask Out Hi Bit
  2176.     MOV        BX, CHARSET_HI        ; BX = Char Set Ptr:Offset
  2177.     MOV        DX, CHARSET_HI+2    ; DX = Char Set Ptr:Segment
  2178.     JMP        s @TGP_Set_Char        ; Go Setup Character Ptr
  2179.  
  2180. @TGP_LowChar:
  2181.  
  2182.     MOV        BX, CHARSET_LOW        ; BX = Char Set Ptr:Offset
  2183.     MOV        DX, CHARSET_LOW+2    ; DX = Char Set Ptr:Segment
  2184.  
  2185. @TGP_Set_Char:
  2186.     MOV        [BP].TGP_T_SETS, DX    ; Save Segment on Stack
  2187.  
  2188.     MOV     AH, 0                   ; Valid #'s are 0..127
  2189.     SHL     AX, 3               ; * 8 Bytes Per Bitmap
  2190.     ADD        BX, AX                ; BX = Offset of Selected char
  2191.     MOV        [BP].TGP_T_SETO, BX    ; Save Offset on Stack
  2192.  
  2193.     AND        CX, PLANE_BITS        ; Get Plane #
  2194.     MOV        CH, ALL_PLANES        ; Get Initial Plane mask
  2195.     SHL        CH, CL                ; And shift into position
  2196.     AND        CH, ALL_PLANES        ; And mask to lower nibble
  2197.  
  2198.     MOV        AL, 04                ; 4-Plane # = # of initial
  2199.     SUB        AL, CL                ; shifts to align bit mask 
  2200.     MOV        CL, AL                ; Shift Count for SHL
  2201.     
  2202.     ;Get segment of character map
  2203.  
  2204.     OUT_8    SC_Index, MAP_MASK    ; Setup Plane selections
  2205.     INC        DX                    ; DX -> SC_Data
  2206.  
  2207.     MOV        AL, 08                ; 8 Lines to Process
  2208.     MOV        [BP].TGP_Lines, AL    ; Save on Stack
  2209.  
  2210.     MOV        DS, [BP].TGP_T_SETS    ; Point to character set
  2211.  
  2212. @TGP_DECODE_CHAR_BYTE:
  2213.  
  2214.     MOV     SI, [BP].TGP_T_SETO ; Get DS:SI = String
  2215.  
  2216.     MOV        BH, [SI]            ; Get Bit Map
  2217.     INC        SI                    ; Point to Next Line
  2218.     MOV     [BP].TGP_T_SETO, SI    ; And save new Pointer...
  2219.  
  2220.     MOV        AH, [BP].TGP_ColorF    ; Get Foreground Color
  2221.  
  2222.     CLR        BL                        ; Clear BL
  2223.     ROL        BX, CL                    ; BL holds left edge bits
  2224.     MOV        SI, BX                     ; Use as Table Index
  2225.     AND        SI, CHAR_BITS            ; Get Low Bits
  2226.     MOV        AL, Char_Plane_Data[SI]    ; Get Mask in AL
  2227.     JZ        @TGP_NO_LEFT1BITS        ; Skip if No Pixels to set
  2228.  
  2229.     OUT        DX, AL                ; Set up Screen Mask
  2230.     MOV        ES:[DI], AH            ; Write Foreground color
  2231.  
  2232.     ;Now Do Middle/Last Band
  2233.  
  2234. @TGP_NO_LEFT1BITS:
  2235.  
  2236.     INC        DI                    ; Point to next Byte
  2237.     ROL        BX, 4                ; Shift 4 bits
  2238.     
  2239.     MOV        SI, BX                     ; Make Lookup Pointer
  2240.     AND        SI, CHAR_BITS            ; Get Low Bits
  2241.     MOV        AL, Char_Plane_Data[SI]    ; Get Mask in AL
  2242.     JZ        @TGP_NO_MIDDLE1BITS        ; Skip if no pixels to set
  2243.  
  2244.     OUT        DX, AL                ; Set up Screen Mask
  2245.     MOV        ES:[DI], AH            ; Write Foreground color
  2246.  
  2247. @TGP_NO_MIDDLE1BITS:
  2248.     XOR        CH, ALL_PLANES        ; Invert Clip Mask
  2249.     CMP        CL, 4                ; Aligned by 4?
  2250.     JZ        @TGP_NEXT_LINE        ; If so, Exit now..
  2251.  
  2252.     INC        DI                    ; Point to next Byte
  2253.     ROL        BX, 4                ; Shift 4 bits
  2254.  
  2255.     MOV        SI, BX                     ; Make Lookup Pointer
  2256.     AND        SI, CHAR_BITS            ; Get Low Bits
  2257.     MOV        AL, Char_Plane_Data[SI]    ; Get Mask in AL
  2258.     JZ        @TGP_NO_RIGHT1BITS        ; Skip if No Pixels to set
  2259.  
  2260.     OUT        DX, AL                ; Set up Screen Mask
  2261.     MOV        ES:[DI], AH            ; Write Foreground color
  2262.  
  2263. @TGP_NO_RIGHT1BITS:
  2264.  
  2265.     DEC        DI                    ; Adjust for Next Line Advance
  2266.  
  2267. @TGP_NEXT_LINE:
  2268.     ADD        DI, [BP].TGP_Width    ; Point to Next Line
  2269.     XOR        CH, CHAR_BITS        ; Flip the Clip mask back
  2270.  
  2271.     DEC        [BP].TGP_Lines        ; Count Down Lines
  2272.     JZ        @TGP_EXIT            ; Ok... Done!
  2273.  
  2274.     JMP        @TGP_DECODE_CHAR_BYTE    ; Again! Hey!
  2275.  
  2276. @TGP_EXIT:
  2277.     ADD        SP, 08                ; Deallocate stack workspace
  2278.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2279.     RET     8                     ; Exit and Clean up Stack
  2280.  
  2281. TGPRINTC      ENDP
  2282.  
  2283.  
  2284. ;===============================================================
  2285. ;PRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
  2286. ;===============================================================
  2287. ;
  2288. ; Routine to quickly Print a null terminated ASCII string on the 
  2289. ; active display page up to a maximum length.
  2290. ;
  2291. ; ENTRY: String  = Far Pointer to ASCII string to print
  2292. ;        MaxLen  = # of characters to print if no null found
  2293. ;         Xpos    = X position to draw Text at
  2294. ;        Ypos    = Y position of to draw Text at
  2295. ;        ColorF  = Color to draw text in
  2296. ;        ColorB  = Color to set background to
  2297. ;
  2298. ; EXIT:  No meaningful values returned
  2299. ;
  2300.  
  2301. PS_STACK    STRUC
  2302.                     DW    ?x4    ; DI, SI, DS, BP
  2303.                 DD    ?    ; Caller
  2304.     PS_ColorB    DW    ?    ; Background Color
  2305.     PS_ColorF    DW    ?    ; Text Color
  2306.     PS_Ypos        DW    ?    ; Y Position to Print at
  2307.     PS_Xpos        DW    ?    ; X position to Print at
  2308.     PS_Len        DW    ?    ; Maximum Length of string to print
  2309.     PS_Text        DW    ?,?    ; Far Ptr to Text String
  2310. PS_STACK    ENDS
  2311.  
  2312.         PUBLIC    PRINT_STR
  2313.  
  2314. PRINT_STR    PROC    FAR
  2315.  
  2316.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2317.     MOV        BP, SP                ; Set up Stack Frame
  2318.  
  2319. @PS_Print_It:
  2320.  
  2321.     MOV        CX, [BP].PS_Len        ; Get Remaining text Length
  2322.     JCXZ    @PS_Exit            ; Exit when out of text
  2323.  
  2324.     LES        DI, d [BP].PS_Text    ; ES:DI -> Current Char in Text
  2325.     MOV        AL, ES:[DI]            ; AL = Text Character
  2326.     AND        AX, 00FFh            ; Clear High Word
  2327.     JZ        @PS_Exit            ; Exit if null character
  2328.  
  2329.     DEC        [BP].PS_Len            ; Remaining Text length--
  2330.     INC        [BP].PS_Text        ; Point to Next text char
  2331.  
  2332.     ; Set up Call to GPRINTC
  2333.  
  2334.     PUSH    AX                    ; Set Character Parameter
  2335.     MOV        BX, [BP].PS_Xpos    ; Get Xpos
  2336.     PUSH    BX                    ; Set Xpos Parameter
  2337.     ADD        BX, 8                ; Advance 1 Char to Right
  2338.     MOV        [BP].PS_Xpos, BX    ; Save for next time through
  2339.  
  2340.     MOV        BX, [BP].PS_Ypos    ; Get Ypos
  2341.     PUSH    BX                    ; Set Ypos Parameter
  2342.  
  2343.     MOV        BX, [BP].PS_ColorF    ; Get Text Color
  2344.     PUSH    BX                    ; Set ColorF Parameter
  2345.  
  2346.     MOV        BX, [BP].PS_ColorB    ; Get Background Color
  2347.     PUSH    BX                    ; Set ColorB Parameter
  2348.  
  2349.     CALL    f GPRINTC            ; Print Character!
  2350.     JMP        s @PS_Print_It        ; Process next character
  2351.  
  2352. @PS_Exit:
  2353.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2354.     RET     14                     ; Exit and Clean up Stack
  2355.  
  2356. PRINT_STR  ENDP
  2357.  
  2358.  
  2359. ;================================================================
  2360. ;TPRINT_STR (SEG String, MaxLen%, Xpos%, Ypos%, ColorF%, ColorB%)
  2361. ;================================================================
  2362. ;
  2363. ; Routine to quickly transparently Print a null terminated ASCII 
  2364. ; string on the active display page up to a maximum length.
  2365. ;
  2366. ; ENTRY: String  = Far Pointer to ASCII string to print
  2367. ;        MaxLen  = # of characters to print if no null found
  2368. ;         Xpos    = X position to draw Text at
  2369. ;        Ypos    = Y position of to draw Text at
  2370. ;        ColorF  = Color to draw text in
  2371. ;
  2372. ; EXIT:  No meaningful values returned
  2373. ;
  2374.  
  2375. TPS_STACK    STRUC
  2376.                     DW    ?x4    ; DI, SI, DS, BP
  2377.                 DD    ?    ; Caller
  2378.     TPS_ColorF    DW    ?    ; Text Color
  2379.     TPS_Ypos    DW    ?    ; Y Position to Print at
  2380.     TPS_Xpos    DW    ?    ; X position to Print at
  2381.     TPS_Len        DW    ?    ; Maximum Length of string to print
  2382.     TPS_Text    DW    ?,?    ; Far Ptr to Text String
  2383. TPS_STACK    ENDS
  2384.  
  2385.         PUBLIC    TPRINT_STR
  2386.  
  2387. TPRINT_STR    PROC    FAR
  2388.  
  2389.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2390.     MOV        BP, SP                ; Set up Stack Frame
  2391.  
  2392. @TPS_Print_It:
  2393.  
  2394.     MOV        CX, [BP].TPS_Len    ; Get Remaining text Length
  2395.     JCXZ    @TPS_Exit            ; Exit when out of text
  2396.  
  2397.     LES        DI, d [BP].TPS_Text    ; ES:DI -> Current Char in Text
  2398.     MOV        AL, ES:[DI]            ; AL = Text Character
  2399.     AND        AX, 00FFh            ; Clear High Word
  2400.     JZ        @TPS_Exit            ; Exit if null character
  2401.  
  2402.     DEC        [BP].TPS_Len        ; Remaining Text length--
  2403.     INC        [BP].TPS_Text        ; Point to Next text char
  2404.  
  2405.     ; Set up Call to TGPRINTC
  2406.  
  2407.     PUSH    AX                    ; Set Character Parameter
  2408.     MOV        BX, [BP].TPS_Xpos    ; Get Xpos
  2409.     PUSH    BX                    ; Set Xpos Parameter
  2410.     ADD        BX, 8                ; Advance 1 Char to Right
  2411.     MOV        [BP].TPS_Xpos, BX    ; Save for next time through
  2412.  
  2413.     MOV        BX, [BP].TPS_Ypos    ; Get Ypos
  2414.     PUSH    BX                    ; Set Ypos Parameter
  2415.  
  2416.     MOV        BX, [BP].TPS_ColorF    ; Get Text Color
  2417.     PUSH    BX                    ; Set ColorF Parameter
  2418.  
  2419.     CALL    f TGPRINTC            ; Print Character!
  2420.     JMP        s @TPS_Print_It        ; Process next character
  2421.  
  2422. @TPS_Exit:
  2423.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2424.     RET     12                     ; Exit and Clean up Stack
  2425.  
  2426. TPRINT_STR  ENDP
  2427.  
  2428.  
  2429. ;===========================================
  2430. ;SET_DISPLAY_FONT(SEG FontData, FontNumber%)
  2431. ;===========================================
  2432. ;
  2433. ; Allows the user to specify their own font data for
  2434. ; wither the lower or upper 128 characters.
  2435. ;
  2436. ; ENTRY: FontData   = Far Pointer to Font Bitmaps
  2437. ;        FontNumber = Which half of set this is
  2438. ;                   = 0, Lower 128 characters
  2439. ;                   = 1, Upper 128 characters
  2440. ;
  2441. ; EXIT:  No meaningful values returned
  2442. ;
  2443.  
  2444. SDF_STACK    STRUC
  2445.                 DW    ?    ; BP
  2446.                 DD    ?    ; Caller
  2447.     SDF_Which    DW    ?    ; Hi Table/Low Table Flag
  2448.     SDF_Font    DD    ?    ; Far Ptr to Font Table
  2449. SDF_STACK    ENDS
  2450.  
  2451.     PUBLIC    SET_DISPLAY_FONT
  2452.  
  2453. SET_DISPLAY_FONT    PROC    FAR
  2454.  
  2455.     PUSH    BP                    ; Preserve Registers
  2456.     MOV        BP, SP                ; Set up Stack Frame
  2457.  
  2458.     LES        DI, [BP].SDF_Font    ; Get Far Ptr to Font
  2459.  
  2460.     MOV        SI, o CHARSET_LOW    ; Assume Lower 128 chars
  2461.     TEST    [BP].SDF_Which, 1    ; Font #1 selected?
  2462.     JZ        @SDF_Set_Font        ; If not, skip ahead
  2463.  
  2464.     MOV        SI, o CHARSET_HI    ; Ah, really it's 128-255
  2465.  
  2466. @SDF_Set_Font:
  2467.     MOV        [SI], DI            ; Set Font Pointer Offset
  2468.     MOV        [SI+2], ES            ; Set Font Pointer Segment
  2469.  
  2470.     POP        BP                    ; Restore Registers
  2471.     RET     6                    ; We are Done.. Outa here
  2472.  
  2473. SET_DISPLAY_FONT    ENDP
  2474.  
  2475.  
  2476.     ; ===== BITMAP (SPRITE) DISPLAY ROUTINES =====
  2477.  
  2478. ;======================================================
  2479. ;DRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
  2480. ;======================================================
  2481. ;
  2482. ; Draws a variable sized Graphics Bitmap such as a
  2483. ; picture or an Icon on the current Display Page in
  2484. ; Mode X.  The Bitmap is stored in a linear byte array
  2485. ; corresponding to (0,0) (1,0), (2,0) .. (Width, Height)
  2486. ; This is the same linear manner as mode 13h graphics.
  2487. ;
  2488. ; ENTRY: Image  = Far Pointer to Bitmap Data
  2489. ;         Xpos   = X position to Place Upper Left pixel at        
  2490. ;         Ypos   = Y position to Place Upper Left pixel at        
  2491. ;         Width  = Width of the Bitmap in Pixels
  2492. ;        Height    = Height of the Bitmap in Pixels
  2493. ;
  2494. ; EXIT:  No meaningful values returned
  2495. ;
  2496.  
  2497. DB_STACK    STRUC
  2498.     DB_LineO    DW    ?    ; Offset to Next Line
  2499.     DB_PixCount    DW    ?    ; (Minimum) # of Pixels/Line
  2500.     DB_Start    DW    ?    ; Addr of Upper Left Pixel
  2501.     DB_PixSkew    DW    ?    ; # of bytes to Adjust EOL
  2502.     DB_SkewFlag    DW    ?    ; Extra Pix on Plane Flag
  2503.                 DW    ?x4    ; DI, SI, DS, BP
  2504.                 DD    ?    ; Caller
  2505.     DB_Height    DW    ?    ; Height of Bitmap in Pixels
  2506.     DB_Width    DW    ?    ; Width of Bitmap in Pixels
  2507.     DB_Ypos        DW    ?     ; Y position to Draw Bitmap at
  2508.     DB_Xpos        DW    ?    ; X position to Draw Bitmap at
  2509.     DB_Image    DD    ?    ; Far Pointer to Graphics Bitmap
  2510. DB_STACK    ENDS
  2511.  
  2512.         PUBLIC    DRAW_BITMAP
  2513.  
  2514. DRAW_BITMAP    PROC    FAR
  2515.  
  2516.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2517.     SUB        SP, 10                ; Allocate workspace
  2518.     MOV        BP, SP                ; Set up Stack Frame
  2519.  
  2520.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  2521.     CLD                            ; Direction Flag = Forward
  2522.  
  2523.     MOV        AX, [BP].DB_Ypos    ; Get UL Corner Ypos
  2524.     MUL        SCREEN_WIDTH        ; AX = Offset to Line Ypos
  2525.  
  2526.     MOV        BX, [BP].DB_Xpos    ; Get UL Corner Xpos
  2527.     MOV        CL, BL                ; Save Plane # in CL
  2528.     SHR        BX, 2                ; Xpos/4 = Offset Into Line
  2529.  
  2530.     ADD        DI, AX                ; ES:DI -> Start of Line
  2531.     ADD        DI, BX                ; ES:DI -> Upper Left Pixel
  2532.     MOV        [BP].DB_Start, DI    ; Save Starting Addr
  2533.  
  2534.     ; Compute line to line offset
  2535.  
  2536.     MOV        BX, [BP].DB_Width    ; Get Width of Image
  2537.     MOV        DX, BX                ; Save Copy in DX
  2538.     SHR        BX, 2                ; /4 = width in bands
  2539.     MOV        AX, SCREEN_WIDTH    ; Get Screen Width
  2540.     SUB        AX, BX                ; - (Bitmap Width/4)
  2541.  
  2542.     MOV        [BP].DB_LineO, AX        ; Save Line Width offset
  2543.     MOV        [BP].DB_PixCount, BX    ; Minimum # pix to copy
  2544.  
  2545.     AND        DX, PLANE_BITS            ; Get "partial band" size (0-3)
  2546.     MOV        [BP].DB_PixSkew, DX        ; Also End of Line Skew
  2547.     MOV        [BP].DB_SkewFlag, DX    ; Save as Flag/Count
  2548.  
  2549.     AND        CX, PLANE_BITS        ; CL = Starting Plane #            
  2550.     MOV        AX, MAP_MASK_PLANE2    ; Plane Mask & Plane Select
  2551.     SHL        AH, CL                ; Select correct Plane
  2552.     OUT_16    SC_Index, AX        ; Select Plane...
  2553.     MOV        BH, AH                ; BH = Saved Plane Mask
  2554.     MOV        BL, 4                ; BL = Planes to Copy
  2555.  
  2556. @DB_COPY_PLANE:
  2557.  
  2558.     LDS        SI, [BP].DB_Image    ; DS:SI-> Source Image
  2559.     MOV        DX, [BP].DB_Height    ; # of Lines to Copy
  2560.     MOV        DI, [BP].DB_Start    ; ES:DI-> Dest pos
  2561.  
  2562. @DB_COPY_LINE:
  2563.     MOV        CX, [BP].DB_PixCount    ; Min # to copy
  2564.  
  2565.     TEST    CL, 0FCh            ; 16+PixWide?
  2566.     JZ        @DB_COPY_REMAINDER    ; Nope...
  2567.  
  2568.     ; Pixel Copy loop has been unrolled to x4
  2569.                 
  2570. @DB_COPY_LOOP:
  2571.     MOVSB                       ; Copy Bitmap Pixel 
  2572.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2573.     MOVSB                       ; Copy Bitmap Pixel 
  2574.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2575.     MOVSB                       ; Copy Bitmap Pixel 
  2576.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2577.     MOVSB                       ; Copy Bitmap Pixel 
  2578.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2579.  
  2580.     SUB        CL, 4                ; Pixels to Copy=-4
  2581.     TEST    CL, 0FCh            ; 4+ Pixels Left?
  2582.     JNZ        @DB_COPY_LOOP        ; if so, do another block
  2583.  
  2584. @DB_COPY_REMAINDER:
  2585.     JCXZ    @DB_NEXT_LINE        ; Any Pixels left on line
  2586.  
  2587. @DB_COPY2:
  2588.     MOVSB                       ; Copy Bitmap Pixel 
  2589.     ADD        SI,3                ; Skip to Next Byte in same plane
  2590.     LOOPx    CX,    @DB_COPY2        ; Pixels to Copy--, Loop until done
  2591.  
  2592. @DB_NEXT_LINE:
  2593.  
  2594.     ; any Partial Pixels? (some planes only)
  2595.  
  2596.     OR        CX, [BP].DB_SkewFlag    ; Get Skew Count
  2597.     JZ        @DB_NEXT2                ; if no partial pixels
  2598.  
  2599.     MOVSB                       ; Copy Bitmap Pixel 
  2600.     DEC        DI                    ; Back up to align
  2601.     DEC        SI                    ; Back up to align
  2602.  
  2603. @DB_NEXT2:
  2604.     ADD        SI, [BP].DB_PixSkew    ; Adjust Skew
  2605.     ADD     DI, [BP].DB_LineO   ; Set to Next Display Line
  2606.     LOOPx    DX, @DB_COPY_LINE    ; Lines to Copy--, Loop if more
  2607.  
  2608.     ; Copy Next Plane....
  2609.  
  2610.     DEC        BL                    ; Planes to Go--
  2611.     JZ        @DB_Exit            ; Hey! We are done
  2612.  
  2613.     ROL        BH, 1                ; Next Plane in line...
  2614.     OUT_8    SC_Data, BH            ; Select Plane
  2615.  
  2616.     CMP        AL, 12h                ; Carry Set if AL=11h
  2617.     ADC        [BP].DB_Start, 0    ; Screen Addr =+Carry    
  2618.     INC        w [BP].DB_Image        ; Start @ Next Byte
  2619.  
  2620.     SUB        [BP].DB_SkewFlag, 1    ; Reduce Planes to Skew
  2621.     ADC        [BP].DB_SkewFlag, 0 ; Back to 0 if it was -1
  2622.  
  2623.     JMP        s @DB_COPY_PLANE    ; Go Copy the Next Plane
  2624.  
  2625. @DB_Exit:
  2626.     ADD        SP, 10                ; Deallocate workspace
  2627.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2628.     RET     12                     ; Exit and Clean up Stack
  2629.  
  2630. DRAW_BITMAP   ENDP
  2631.  
  2632.  
  2633. ;=======================================================
  2634. ;TDRAW_BITMAP (SEG Image, Xpos%, Ypos%, Width%, Height%)
  2635. ;=======================================================
  2636. ;
  2637. ; Transparently Draws a variable sized Graphics Bitmap 
  2638. ; such as a picture or an Icon on the current Display Page
  2639. ; in Mode X.  Pixels with a value of 0 are not drawn,
  2640. ; leaving the previous "background" contents intact.
  2641. ;
  2642. ; The Bitmap format is the same as for the DRAW_BITMAP function.
  2643. ;
  2644. ; ENTRY: Image  = Far Pointer to Bitmap Data
  2645. ;         Xpos   = X position to Place Upper Left pixel at        
  2646. ;         Ypos   = Y position to Place Upper Left pixel at        
  2647. ;         Width  = Width of the Bitmap in Pixels
  2648. ;        Height    = Height of the Bitmap in Pixels
  2649. ;
  2650. ; EXIT:  No meaningful values returned
  2651. ;
  2652.  
  2653. TB_STACK    STRUC
  2654.     TB_LineO    DW    ?    ; Offset to Next Line
  2655.     TB_PixCount    DW    ?    ; (Minimum) # of Pixels/Line
  2656.     TB_Start    DW    ?    ; Addr of Upper Left Pixel
  2657.     TB_PixSkew    DW    ?    ; # of bytes to Adjust EOL
  2658.     TB_SkewFlag    DW    ?    ; Extra Pix on Plane Flag
  2659.                 DW    ?x4    ; DI, SI, DS, BP
  2660.                 DD    ?    ; Caller
  2661.     TB_Height    DW    ?    ; Height of Bitmap in Pixels
  2662.     TB_Width    DW    ?    ; Width of Bitmap in Pixels
  2663.     TB_Ypos        DW    ?     ; Y position to Draw Bitmap at
  2664.     TB_Xpos        DW    ?    ; X position to Draw Bitmap at
  2665.     TB_Image    DD    ?    ; Far Pointer to Graphics Bitmap
  2666. TB_STACK    ENDS
  2667.  
  2668.         PUBLIC    TDRAW_BITMAP
  2669.  
  2670. TDRAW_BITMAP    PROC    FAR
  2671.  
  2672.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2673.     SUB        SP, 10                ; Allocate workspace
  2674.     MOV        BP, SP                ; Set up Stack Frame
  2675.  
  2676.     LES        DI, d CURRENT_PAGE    ; Point to Active VGA Page
  2677.     CLD                            ; Direction Flag = Forward
  2678.  
  2679.     MOV        AX, [BP].TB_Ypos    ; Get UL Corner Ypos
  2680.     MUL        SCREEN_WIDTH        ; AX = Offset to Line Ypos
  2681.  
  2682.     MOV        BX, [BP].TB_Xpos    ; Get UL Corner Xpos
  2683.     MOV        CL, BL                ; Save Plane # in CL
  2684.     SHR        BX, 2                ; Xpos/4 = Offset Into Line
  2685.  
  2686.     ADD        DI, AX                ; ES:DI -> Start of Line
  2687.     ADD        DI, BX                ; ES:DI -> Upper Left Pixel
  2688.     MOV        [BP].TB_Start, DI    ; Save Starting Addr
  2689.  
  2690.     ; Compute line to line offset
  2691.  
  2692.     MOV        BX, [BP].TB_Width    ; Get Width of Image
  2693.     MOV        DX, BX                ; Save Copy in DX
  2694.     SHR        BX, 2                ; /4 = width in bands
  2695.     MOV        AX, SCREEN_WIDTH    ; Get Screen Width
  2696.     SUB        AX, BX                ; - (Bitmap Width/4)
  2697.  
  2698.     MOV        [BP].TB_LineO, AX        ; Save Line Width offset
  2699.     MOV        [BP].TB_PixCount, BX    ; Minimum # pix to copy
  2700.  
  2701.     AND        DX, PLANE_BITS            ; Get "partial band" size (0-3)
  2702.     MOV        [BP].TB_PixSkew, DX        ; Also End of Line Skew
  2703.     MOV        [BP].TB_SkewFlag, DX    ; Save as Flag/Count
  2704.             
  2705.     AND        CX, PLANE_BITS        ; CL = Starting Plane #
  2706.     MOV        AX, MAP_MASK_PLANE2    ; Plane Mask & Plane Select
  2707.     SHL        AH, CL                ; Select correct Plane
  2708.     OUT_16    SC_Index, AX        ; Select Plane...
  2709.     MOV        BH, AH                ; BH = Saved Plane Mask
  2710.     MOV        BL, 4                ; BL = Planes to Copy
  2711.  
  2712. @TB_COPY_PLANE:
  2713.  
  2714.     LDS        SI, [BP].TB_Image    ; DS:SI-> Source Image
  2715.     MOV        DX, [BP].TB_Height    ; # of Lines to Copy
  2716.     MOV        DI, [BP].TB_Start    ; ES:DI-> Dest pos
  2717.  
  2718.     ; Here AH is set with the value to be considered
  2719.     ; "Transparent".  It can be changed!
  2720.  
  2721.     MOV        AH, 0                ; Value to Detect 0
  2722.  
  2723. @TB_COPY_LINE:
  2724.     MOV        CX, [BP].TB_PixCount    ; Min # to copy
  2725.  
  2726.     TEST    CL, 0FCh            ; 16+PixWide?
  2727.     JZ        @TB_COPY_REMAINDER    ; Nope...
  2728.  
  2729.     ; Pixel Copy loop has been unrolled to x4
  2730.                 
  2731. @TB_COPY_LOOP:
  2732.     LODSB                        ; Get Pixel Value in AL
  2733.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2734.     CMP        AL, AH                ; It is "Transparent"?
  2735.     JE        @TB_SKIP_01            ; Skip ahead if so
  2736.     MOV        ES:[DI], AL            ; Copy Pixel to VGA screen
  2737.  
  2738. @TB_SKIP_01:
  2739.     LODSB                        ; Get Pixel Value in AL
  2740.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2741.     CMP        AL, AH                ; It is "Transparent"?
  2742.     JE        @TB_SKIP_02            ; Skip ahead if so
  2743.     MOV        ES:[DI+1], AL        ; Copy Pixel to VGA screen
  2744.  
  2745. @TB_SKIP_02:
  2746.     LODSB                        ; Get Pixel Value in AL
  2747.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2748.     CMP        AL, AH                ; It is "Transparent"?
  2749.     JE        @TB_SKIP_03            ; Skip ahead if so
  2750.     MOV        ES:[DI+2], AL        ; Copy Pixel to VGA screen
  2751.  
  2752. @TB_SKIP_03:
  2753.     LODSB                        ; Get Pixel Value in AL
  2754.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2755.     CMP        AL, AH                ; It is "Transparent"?
  2756.     JE        @TB_SKIP_04            ; Skip ahead if so
  2757.     MOV        ES:[DI+3], AL        ; Copy Pixel to VGA screen
  2758.  
  2759. @TB_SKIP_04:
  2760.     ADD        DI, 4                ; Adjust Pixel Write Location
  2761.     SUB        CL, 4                ; Pixels to Copy=-4
  2762.     TEST    CL, 0FCh            ; 4+ Pixels Left?
  2763.     JNZ        @TB_COPY_LOOP        ; if so, do another block
  2764.  
  2765. @TB_COPY_REMAINDER:
  2766.     JCXZ    @TB_NEXT_LINE        ; Any Pixels left on line
  2767.  
  2768. @TB_COPY2:
  2769.     LODSB                        ; Get Pixel Value in AL
  2770.     ADD        SI, 3                ; Skip to Next Byte in same plane
  2771.     CMP        AL, AH                ; It is "Transparent"?
  2772.     JE        @TB_SKIP_05            ; Skip ahead if so
  2773.     MOV        ES:[DI], AL            ; Copy Pixel to VGA screen
  2774.  
  2775. @TB_SKIP_05:
  2776.     INC        DI                    ; Advance Dest Addr
  2777.     LOOPx    CX, @TB_COPY2        ; Pixels to Copy--, Loop until done
  2778.  
  2779. @TB_NEXT_LINE:
  2780.  
  2781.     ; any Partial Pixels? (some planes only)
  2782.  
  2783.     OR        CX, [BP].TB_SkewFlag    ; Get Skew Count
  2784.     JZ        @TB_NEXT2                ; if no partial pixels
  2785.  
  2786.     LODSB                        ; Get Pixel Value in AL
  2787.     DEC        SI                    ; Backup to Align
  2788.     CMP        AL, AH                ; It is "Transparent"?
  2789.     JE        @TB_NEXT2            ; Skip ahead if so
  2790.     MOV        ES:[DI], AL            ; Copy Pixel to VGA screen
  2791.  
  2792. @TB_NEXT2:
  2793.     ADD        SI, [BP].TB_PixSkew    ; Adjust Skew
  2794.     ADD     DI, [BP].TB_LineO   ; Set to Next Display Line
  2795.     LOOPx    DX, @TB_COPY_LINE    ; Lines to Copy--, Loop if More
  2796.  
  2797.     ;Copy Next Plane....
  2798.  
  2799.     DEC        BL                    ; Planes to Go--
  2800.     JZ        @TB_Exit            ; Hey! We are done
  2801.  
  2802.     ROL        BH, 1                ; Next Plane in line...
  2803.     OUT_8    SC_Data, BH            ; Select Plane
  2804.  
  2805.     CMP        AL, 12h                ; Carry Set if AL=11h
  2806.     ADC        [BP].TB_Start, 0    ; Screen Addr =+Carry    
  2807.     INC        w [BP].TB_Image        ; Start @ Next Byte
  2808.  
  2809.     SUB        [BP].TB_SkewFlag, 1    ; Reduce Planes to Skew
  2810.     ADC        [BP].TB_SkewFlag, 0 ; Back to 0 if it was -1
  2811.  
  2812.     JMP        @TB_COPY_PLANE        ; Go Copy the next Plane
  2813.  
  2814. @TB_Exit:
  2815.     ADD        SP, 10                ; Deallocate workspace
  2816.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2817.     RET     12                     ; Exit and Clean up Stack
  2818.  
  2819. TDRAW_BITMAP    ENDP
  2820.  
  2821.  
  2822.     ; ==== VIDEO MEMORY to VIDEO MEMORY COPY ROUTINES =====
  2823.  
  2824. ;==================================
  2825. ;COPY_PAGE (SourcePage%, DestPage%)
  2826. ;==================================
  2827. ;
  2828. ; Duplicate on display page onto another
  2829. ;
  2830. ; ENTRY: SourcePage = Display Page # to Duplicate
  2831. ;         DestPage   = Display Page # to hold copy
  2832. ;
  2833. ; EXIT:  No meaningful values returned
  2834. ;
  2835.  
  2836. CP_STACK    STRUC
  2837.                 DW    ?x4    ; DI, SI, DS, BP
  2838.                 DD    ?    ; Caller
  2839.     CP_DestP    DW    ?    ; Page to hold copied image
  2840.     CP_SourceP    DW    ?    ; Page to Make copy from
  2841. CP_STACK    ENDS
  2842.  
  2843.         PUBLIC    COPY_PAGE
  2844.  
  2845. COPY_PAGE    PROC    FAR
  2846.  
  2847.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2848.     MOV        BP, SP                ; Set up Stack Frame
  2849.     CLD                            ; Block Xfer Forwards
  2850.  
  2851.     ; Make sure Page #'s are valid
  2852.  
  2853.     MOV        AX, [BP].CP_SourceP    ; Get Source Page #
  2854.     CMP        AX, LAST_PAGE        ; is it > Max Page #?
  2855.     JAE        @CP_Exit            ; if so, abort
  2856.  
  2857.     MOV        BX, [BP].CP_DestP    ; Get Destination Page #
  2858.     CMP        BX, LAST_PAGE        ; is it > Max Page #?
  2859.     JAE        @CP_Exit            ; if so, abort
  2860.  
  2861.     CMP        AX, BX                ; Pages #'s the same?
  2862.     JE        @CP_Exit            ; if so, abort
  2863.  
  2864.     ; Setup DS:SI and ES:DI to Video Pages
  2865.  
  2866.     SHL        BX, 1                ; Scale index to Word
  2867.     MOV        DI, PAGE_ADDR[BX]    ; Offset to Dest Page
  2868.     
  2869.     MOV        BX, AX                ; Index to Source page
  2870.     SHL        BX, 1                ; Scale index to Word
  2871.     MOV        SI, PAGE_ADDR[BX]    ; Offset to Source Page
  2872.  
  2873.     MOV        CX, PAGE_SIZE        ; Get size of Page
  2874.     MOV        AX, CURRENT_SEGMENT    ; Get Video Mem Segment
  2875.     MOV        ES, AX                ; ES:DI -> Dest Page
  2876.     MOV        DS, AX                ; DS:SI -> Source Page
  2877.  
  2878.     ; Setup VGA registers for Mem to Mem copy
  2879.  
  2880.     OUT_16    GC_Index, LATCHES_ON    ; Data from Latches = on
  2881.     OUT_16    SC_Index, ALL_PLANES_ON ; Copy all Planes
  2882.  
  2883.     ; Note.. Do *NOT* use MOVSW or MOVSD - they will
  2884.     ; Screw with the latches which are 8 bits x 4
  2885.  
  2886.     REP        MOVSB                ; Copy entire Page!
  2887.  
  2888.     ; Reset VGA for normal memory access
  2889.  
  2890.     OUT_16    GC_Index, LATCHES_OFF     ; Data from Latches = off
  2891.  
  2892. @CP_Exit:
  2893.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  2894.     RET     4                     ; Exit and Clean up Stack
  2895.  
  2896. COPY_PAGE    ENDP
  2897.  
  2898.  
  2899. ;==========================================================================
  2900. ;COPY_BITMAP (SourcePage%, X1%, Y1%, X2%, Y2%, DestPage%, DestX1%, DestY1%)
  2901. ;==========================================================================
  2902. ;
  2903. ; Copies a Bitmap Image from one Display Page to Another
  2904. ; This Routine is Limited to copying Images with the same
  2905. ; Plane Alignment.  To Work: (X1 MOD 4) must = (DestX1 MOD 4)
  2906. ; Copying an Image to the Same Page is supported, but results
  2907. ; may be defined when the when the rectangular areas
  2908. ; (X1, Y1) - (X2, Y2) and (DestX1, DestY1) - 
  2909. ; (DestX1+(X2-X1), DestY1+(Y2-Y1)) overlap...
  2910. ; No Paramter checking to done to insure that 
  2911. ; X2 >= X1 and Y2 >= Y1.  Be Careful...
  2912. ;
  2913. ; ENTRY: SourcePage = Display Page # with Source Image
  2914. ;        X1         = Upper Left Xpos of Source Image
  2915. ;         Y1         = Upper Left Ypos of Source Image
  2916. ;        X2         = Lower Right Xpos of Source Image
  2917. ;         Y2         = Lower Right Ypos of Source Image
  2918. ;         DestPage   = Display Page # to copy Image to
  2919. ;        DestX1     = Xpos to Copy UL Corner of Image to
  2920. ;         DestY1     = Ypos to Copy UL Corner of Image to
  2921. ;
  2922. ; EXIT:  AX = Success Flag:   0 = Failure / -1= Success
  2923. ;
  2924.  
  2925. CB_STACK    STRUC
  2926.     CB_Height    DW    ?    ; Height of Image in Lines
  2927.     CB_Width    DW    ?    ; Width of Image in "bands"
  2928.                 DW    ?x4    ; DI, SI, DS, BP
  2929.                 DD    ?    ; Caller
  2930.     CB_DestY1    DW    ?    ; Destination Ypos
  2931.     CB_DestX1    DW    ?    ; Destination Xpos
  2932.     CB_DestP    DW    ?    ; Page to Copy Bitmap To
  2933.     CB_Y2        DW    ?    ; LR Ypos of Image
  2934.     CB_X2        DW    ?    ; LR Xpos of Image
  2935.     CB_Y1        DW    ?    ; UL Ypos of Image
  2936.     CB_X1        DW    ?    ; UL Xpos of Image
  2937.     CB_SourceP    DW    ?    ; Page containing Source Bitmap
  2938. CB_STACK    ENDS
  2939.  
  2940.         PUBLIC    COPY_BITMAP
  2941.  
  2942. COPY_BITMAP    PROC    FAR
  2943.                                                              
  2944.     PUSHx    BP, DS, SI, DI        ; Preserve Important Registers
  2945.     SUB        SP, 4                ; Allocate WorkSpace on Stack
  2946.     MOV        BP, SP                ; Set up Stack Frame
  2947.  
  2948.     ; Prep Registers (and keep jumps short!)
  2949.  
  2950.     MOV        ES, CURRENT_SEGMENT    ; ES -> VGA Ram
  2951.     CLD                            ; Block Xfer Forwards
  2952.  
  2953.     ; Make sure Parameters are valid
  2954.  
  2955.     MOV        BX, [BP].CB_SourceP    ; Get Source Page #
  2956.     CMP        BX, LAST_PAGE        ; is it > Max Page #?
  2957.     JAE        @CB_Abort            ; if so, abort
  2958.  
  2959.     MOV        CX, [BP].CB_DestP    ; Get Destination Page #
  2960.     CMP        CX, LAST_PAGE        ; is it > Max Page #?
  2961.     JAE        @CB_Abort            ; if so, abort
  2962.  
  2963.     MOV        AX, [BP].CB_X1        ; Get Source X1
  2964.     XOR        AX, [BP].CB_DestX1    ; Compare Bits 0-1
  2965.     AND        AX, PLANE_BITS        ; Check Plane Bits
  2966.     JNZ        @CB_Abort            ; They should cancel out
  2967.  
  2968.     ; Setup for Copy processing
  2969.  
  2970.     OUT_8    SC_INDEX, MAP_MASK        ; Set up for Plane Select
  2971.     OUT_16    GC_Index, LATCHES_ON    ; Data from Latches = on
  2972.  
  2973.     ; Compute Info About Images, Setup ES:SI & ES:DI
  2974.  
  2975.     MOV        AX, [BP].CB_Y2        ; Height of Bitmap in lines
  2976.     SUB        AX, [BP].CB_Y1        ; is Y2 - Y1 + 1
  2977.     INC        AX                    ; (add 1 since were not 0 based)
  2978.     MOV        [BP].CB_Height, AX    ; Save on Stack for later use
  2979.  
  2980.     MOV        AX, [BP].CB_X2        ; Get # of "Bands" of 4 Pixels 
  2981.     MOV        DX, [BP].CB_X1        ; the Bitmap Occupies as X2-X1
  2982.     SHR        AX, 2                ; Get X2 Band (X2 / 4)
  2983.     SHR        DX, 2                ; Get X1 Band (X1 / 4)
  2984.     SUB        AX, DX                ; AX = # of Bands - 1
  2985.     INC        AX                    ; AX = # of Bands
  2986.     MOV        [BP].CB_Width, AX    ; Save on Stack for later use
  2987.  
  2988.     SHL        BX, 1                ; Scale Source Page to Word
  2989.     MOV        SI, PAGE_ADDR[BX]    ; SI = Offset of Source Page
  2990.     MOV        AX, [BP].CB_Y1        ; Get Source Y1 Line
  2991.     MUL        SCREEN_WIDTH        ; AX = Offset to Line Y1
  2992.     ADD        SI, AX                ; SI = Offset to Line Y1
  2993.     MOV        AX, [BP].CB_X1        ; Get Source X1
  2994.     SHR        AX, 2                ; X1 / 4 = Byte offset
  2995.     ADD        SI, AX                ; SI = Byte Offset to (X1,Y1)
  2996.  
  2997.     MOV        BX, CX                ; Dest Page Index to BX
  2998.     SHL        BX, 1                ; Scale Source Page to Word
  2999.     MOV        DI, PAGE_ADDR[BX]    ; DI = Offset of Dest Page
  3000.     MOV        AX, [BP].CB_DestY1    ; Get Dest Y1 Line
  3001.     MUL        SCREEN_WIDTH        ; AX = Offset to Line Y1
  3002.     ADD        DI, AX                ; DI = Offset to Line Y1
  3003.     MOV        AX, [BP].CB_DestX1    ; Get Dest X1
  3004.     SHR        AX, 2                ; X1 / 4 = Byte offset
  3005.     ADD        DI, AX                ; DI = Byte Offset to (D-X1,D-Y1)
  3006.  
  3007.     MOV        CX, [BP].CB_Width    ; CX = Width of Image (Bands)
  3008.     DEC        CX                    ; CX = 1?
  3009.     JE        @CB_Only_One_Band    ; 0 Means Image Width of 1 Band
  3010.  
  3011.     MOV        BX, [BP].CB_X1        ; Get Source X1
  3012.     AND        BX, PLANE_BITS        ; Aligned? (bits 0-1 = 00?)
  3013.     JZ        @CB_Check_Right        ; if so, check right alignment
  3014.     JNZ        @CB_Left_Band        ; not aligned? well..
  3015.  
  3016. @CB_Abort:
  3017.     CLR        AX                    ; Return False (Failure)
  3018.     JMP        @CB_Exit            ; and Finish Up
  3019.  
  3020.     ; Copy when Left & Right Clip Masks overlap...
  3021.  
  3022. @CB_Only_One_Band:
  3023.     MOV        BX, [BP].CB_X1            ; Get Left Clip Mask
  3024.     AND        BX, PLANE_BITS            ; Mask out Row #    
  3025.     MOV        AL, Left_Clip_Mask[BX]    ; Get Left Edge Mask
  3026.     MOV        BX, [BP].CB_X2             ; Get Right Clip Mask
  3027.     AND        BX, PLANE_BITS            ; Mask out Row #
  3028.     AND        AL, Right_Clip_Mask[BX]    ; Get Right Edge Mask byte
  3029.  
  3030.     OUT_8    SC_Data, AL            ; Clip For Left & Right Masks
  3031.  
  3032.     MOV        CX, [BP].CB_Height    ; CX = # of Lines to Copy
  3033.     MOV        DX, SCREEN_WIDTH    ; DX = Width of Screen
  3034.     CLR        BX                    ; BX = Offset into Image
  3035.  
  3036. @CB_One_Loop:
  3037.     MOV        AL, ES:[SI+BX]        ; Load Latches
  3038.     MOV        ES:[DI+BX], AL        ; Unload Latches
  3039.     ADD        BX, DX                ; Advance Offset to Next Line
  3040.     LOOPjz    CX,    @CB_One_Done    ; Exit Loop if Finished
  3041.  
  3042.     MOV        AL, ES:[SI+BX]        ; Load Latches
  3043.     MOV        ES:[DI+BX], AL        ; Unload Latches
  3044.     ADD        BX, DX                ; Advance Offset to Next Line
  3045.     LOOPx    CX,    @CB_One_Loop    ; Loop until Finished
  3046.  
  3047. @CB_One_Done:
  3048.     JMP        @CB_Finish            ; Outa Here!
  3049.  
  3050.     ; Copy Left Edge of Bitmap
  3051.  
  3052. @CB_Left_Band:
  3053.  
  3054.     OUT_8    SC_Data, Left_Clip_Mask[BX]    ; Set Left Edge Plane Mask 
  3055.  
  3056.     MOV        CX, [BP].CB_Height    ; CX = # of Lines to Copy
  3057.     MOV        DX, SCREEN_WIDTH    ; DX = Width of Screen
  3058.     CLR        BX                    ; BX = Offset into Image
  3059.  
  3060. @CB_Left_Loop:
  3061.     MOV        AL, ES:[SI+BX]        ; Load Latches
  3062.     MOV        ES:[DI+BX], AL        ; Unload Latches
  3063.     ADD        BX, DX                ; Advance Offset to Next Line
  3064.     LOOPjz    CX,    @CB_Left_Done    ; Exit Loop if Finished
  3065.  
  3066.     MOV        AL, ES:[SI+BX]        ; Load Latches
  3067.     MOV        ES:[DI+BX], AL        ; Unload Latches
  3068.     ADD        BX, DX                ; Advance Offset to Next Line
  3069.     LOOPx    CX,    @CB_Left_Loop    ; Loop until Finished
  3070.  
  3071. @CB_Left_Done:
  3072.     INC        DI                    ; Move Dest Over 1 band
  3073.     INC        SI                    ; Move Source Over 1 band
  3074.     DEC        [BP].CB_Width        ; Band Width--
  3075.  
  3076.     ; Determine if Right Edge of Bitmap needs special copy
  3077.  
  3078. @CB_Check_Right:
  3079.     MOV        BX, [BP].CB_X2        ; Get Source X2
  3080.     AND        BX, PLANE_BITS        ; Aligned? (bits 0-1 = 11?)
  3081.     CMP        BL, 03h                ; Plane = 3?
  3082.     JE        @CB_Copy_Middle        ; Copy the Middle then!
  3083.  
  3084.     ; Copy Right Edge of Bitmap
  3085.  
  3086. @CB_Right_Band:
  3087.  
  3088.     OUT_8    SC_Data, Right_Clip_Mask[BX]    ; Set Right Edge Plane Mask 
  3089.  
  3090.     DEC        [BP].CB_Width        ; Band Width--
  3091.     MOV        CX, [BP].CB_Height    ; CX = # of Lines to Copy
  3092.     MOV        DX, SCREEN_WIDTH    ; DX = Width of Screen
  3093.     MOV        BX, [BP].CB_Width    ; BX = Offset to Right Edge
  3094.  
  3095. @CB_Right_Loop:
  3096.     MOV        AL, ES:[SI+BX]        ; Load Latches
  3097.     MOV        ES:[DI+BX], AL        ; Unload Latches
  3098.     ADD        BX, DX                ; Advance Offset to Next Line
  3099.     LOOPjz    CX,    @CB_Right_Done    ; Exit Loop if Finished
  3100.  
  3101.     MOV        AL, ES:[SI+BX]        ; Load Latches
  3102.     MOV        ES:[DI+BX], AL        ; Unload Latches
  3103.     ADD        BX, DX                ; Advance Offset to Next Line
  3104.     LOOPx    CX,    @CB_Right_Loop    ; Loop until Finished
  3105.  
  3106. @CB_Right_Done:
  3107.  
  3108.     ; Copy the Main Block of the Bitmap
  3109.  
  3110. @CB_Copy_Middle:
  3111.  
  3112.     MOV        CX, [BP].CB_Width    ; Get Width Remaining
  3113.     JCXZ    @CB_Finish            ; Exit if Done
  3114.  
  3115.     OUT_8    SC_Data, ALL_PLANES    ; Copy all Planes
  3116.  
  3117.     MOV        DX, SCREEN_WIDTH    ; Get Width of Screen minus
  3118.     SUB        DX, CX                ; Image width (for Adjustment)
  3119.     MOV        AX, [BP].CB_Height    ; AX = # of Lines to Copy
  3120.     MOV        BX, CX                ; BX = Quick REP reload count
  3121.     MOV        CX, ES                ; Move VGA Segment
  3122.     MOV        DS, CX                ; Into DS
  3123.  
  3124.     ; Actual Copy Loop.  REP MOVSB does the work
  3125.  
  3126. @CB_Middle_Copy:
  3127.     MOV        CX, BX                ; Recharge Rep Count
  3128.     REP        MOVSB                ; Move Bands
  3129.     LOOPjz    AX,    @CB_Finish        ; Exit Loop if Finished
  3130.     
  3131.     ADD        SI, DX                ; Adjust DS:SI to Next Line
  3132.     ADD        DI, DX                ; Adjust ES:DI to Next Line
  3133.  
  3134.     MOV        CX, BX                ; Recharge Rep Count
  3135.     REP        MOVSB                ; Move Bands
  3136.     
  3137.     ADD        SI, DX                ; Adjust DS:SI to Next Line
  3138.     ADD        DI, DX                ; Adjust ES:DI to Next Line
  3139.     LOOPx    AX, @CB_Middle_Copy    ; Copy Lines until Done
  3140.  
  3141. @CB_Finish:
  3142.     OUT_16    GC_Index, LATCHES_OFF    ; Data from Latches = on
  3143.  
  3144. @CB_Exit:
  3145.     ADD        SP, 04                ; Deallocate stack workspace
  3146.     POPx    DI, SI, DS, BP        ; Restore Saved Registers
  3147.     RET     16                     ; Exit and Clean up Stack
  3148.  
  3149. COPY_BITMAP    ENDP
  3150.  
  3151.     END                            ; End of Code Segment
  3152.  
  3153.